Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
a3e2b94a
Commit
a3e2b94a
authored
Jul 20, 2014
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes #3611: Refactored query caching.
parent
6a6caf71
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
240 additions
and
44 deletions
+240
-44
caching-data.md
docs/guide/caching-data.md
+81
-14
CHANGELOG.md
framework/CHANGELOG.md
+5
-0
UPGRADE.md
framework/UPGRADE.md
+11
-0
Command.php
framework/db/Command.php
+0
-0
Connection.php
framework/db/Connection.php
+94
-30
CommandTest.php
tests/unit/framework/db/CommandTest.php
+49
-0
No files found.
docs/guide/caching-data.md
View file @
a3e2b94a
...
@@ -245,20 +245,15 @@ Query caching requires a [[yii\db\Connection|DB connection]] and a valid `cache`
...
@@ -245,20 +245,15 @@ Query caching requires a [[yii\db\Connection|DB connection]] and a valid `cache`
The basic usage of query caching is as follows, assuming
`$db`
is a
[
[yii\db\Connection
]
] instance:
The basic usage of query caching is as follows, assuming
`$db`
is a
[
[yii\db\Connection
]
] instance:
```
php
```
php
$duration
=
60
;
// cache query results for 60 seconds.
$result
=
$db
->
cache
(
function
(
$db
)
{
$dependency
=
...
;
// optional dependency
$db
->
beginCache
(
$duration
,
$dependency
);
// ...performs DB queries here...
// the result of the SQL query will be served from the cache
// if query caching is enabled and the query result is found in the cache
return
$db
->
createCommand
(
'SELECT * FROM customer WHERE id=1'
)
->
queryOne
();
$db
->
endCache
(
);
}
);
```
```
As you can see, any SQL queries in between the
`beginCache()`
and
`endCache()`
calls will be cached.
If the result of the same query is found valid in the cache, the query will be skipped and the result
will be served from the cache instead.
Query caching can be used for
[
DAO
](
db-dao.md
)
as well as
[
ActiveRecord
](
db-active-record.md
)
.
Query caching can be used for
[
DAO
](
db-dao.md
)
as well as
[
ActiveRecord
](
db-active-record.md
)
.
> Info: Some DBMS (e.g. [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html))
> Info: Some DBMS (e.g. [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html))
...
@@ -269,13 +264,85 @@ Query caching can be used for [DAO](db-dao.md) as well as [ActiveRecord](db-acti
...
@@ -269,13 +264,85 @@ Query caching can be used for [DAO](db-dao.md) as well as [ActiveRecord](db-acti
### Configurations <a name="query-caching-configs"></a>
### Configurations <a name="query-caching-configs"></a>
Query caching has t
wo
configurable options through
[
[yii\db\Connection
]
]:
Query caching has t
hree global
configurable options through
[
[yii\db\Connection
]
]:
*
[
[yii\db\Connection::enableQueryCache|enableQueryCache
]
]: whether to turn on or off query caching.
It defaults to false. Note that to effectively turn on query caching, you also need to have a valid
cache, as specified by
[
[yii\db\Connection::queryCache|queryCache
]
].
*
[
[yii\db\Connection::queryCacheDuration|queryCacheDuration
]
]: this represents the number of seconds
*
[
[yii\db\Connection::queryCacheDuration|queryCacheDuration
]
]: this represents the number of seconds
that a query result can remain valid in the cache. The duration will be overwritten if you call
that a query result can remain valid in the cache. You can use 0 to indicate a query result should
[
[yii\db\Connection::beginCache()
]
] with an explicit duration parameter.
remain in the cache forever. This property is the default value used when
[
[yii\db\Connection::cache()
]
]
is called without specifying a duration.
*
[
[yii\db\Connection::queryCache|queryCache
]
]: this represents the ID of the cache application component.
*
[
[yii\db\Connection::queryCache|queryCache
]
]: this represents the ID of the cache application component.
It defaults to
`'cache'`
. Query caching is enabled only when there is a valid cache application component.
It defaults to
`'cache'`
. Query caching is enabled only if there is a valid cache application component.
### Usages <<a name="query-caching-usages"></a>
You can use
[
[yii\db\Connection::cache()
]
] if you have multiple SQL queries that need to take advantage of
query caching. The usage is as follows,
```
php
$duration
=
60
;
// cache query results for 60 seconds.
$dependency
=
...
;
// optional dependency
$result
=
$db
->
cache
(
function
(
$db
)
{
// ... perform SQL queries here ...
return
$result
;
},
$duration
,
$dependency
);
```
Any SQL queries in the anonymous function will be cached for the specified duration with the specified dependency.
If the result of a query is found valid in the cache, the query will be skipped and the result will be served
from the cache instead. If you do not specify the
`$duration`
parameter, the value of
[
[yii\db\Connection::queryCacheDuration|queryCacheDuration
]
] will be used instead.
Sometimes within
`cache()`
, you may want to disable query caching for some particular queries. You can use
[
[yii\db\Connection::noCache()
]
] in this case.
```
php
$result
=
$db
->
cache
(
function
(
$db
)
{
// SQL queries that use query caching
$db
->
noCache
(
function
(
$db
)
{
// SQL queries that do not use query caching
});
// ...
return
$result
;
});
```
If you just want to use query caching for a single query, you can call
[
[yii\db\Command::cache()
]
] when building
the command. For example,
```
php
// use query caching and set query cache duration to be 60 seconds
$customer
=
$db
->
createCommand
(
'SELECT * FROM customer WHERE id=1'
)
->
cache
(
60
)
->
queryOne
();
```
You can also use
[
[yii\db\Command::noCache()
]
] to disable query caching for a single command. For example,
```
php
$result
=
$db
->
cache
(
function
(
$db
)
{
// SQL queries that use query caching
// do not use query caching for this command
$customer
=
$db
->
createCommand
(
'SELECT * FROM customer WHERE id=1'
)
->
noCache
()
->
queryOne
();
// ...
return
$result
;
});
```
### Limitations <a name="query-caching-limitations"></a>
### Limitations <a name="query-caching-limitations"></a>
...
...
framework/CHANGELOG.md
View file @
a3e2b94a
...
@@ -167,6 +167,11 @@ Yii Framework 2 Change Log
...
@@ -167,6 +167,11 @@ Yii Framework 2 Change Log
-
Chg #3383: Added
`$type`
parameter to
`IdentityInterface::findIdentityByAccessToken()`
(qiangxue)
-
Chg #3383: Added
`$type`
parameter to
`IdentityInterface::findIdentityByAccessToken()`
(qiangxue)
-
Chg #3531:
\y
ii
\g
rid
\G
ridView now allows any character (except ":") in the attribute part of the shorthand syntax for columns (rawtaz)
-
Chg #3531:
\y
ii
\g
rid
\G
ridView now allows any character (except ":") in the attribute part of the shorthand syntax for columns (rawtaz)
-
Chg #3544: Added
`$key`
as a parameter to the callable specified via
`yii\grid\DataColumn::value`
(mdmunir)
-
Chg #3544: Added
`$key`
as a parameter to the callable specified via
`yii\grid\DataColumn::value`
(mdmunir)
-
Chg #3611: Query caching is refactored. (qiangxue)
-
`yii\db\Connection::beginCache()`
and
`endCache()`
are removed.
-
Added
`yii\db\Connection::cache()`
and
`noCache()`
.
-
Added
`Command::cache()`
and
`noCache()`
.
-
`yii\db\Connection::queryCacheDuration`
is now used as a default cache duration parameter.
-
Chg #3640: All cookies are now httpOnly by default in order to increase overall security (samdark)
-
Chg #3640: All cookies are now httpOnly by default in order to increase overall security (samdark)
-
Chg #3687: Default
`sourceLanguage`
and
`language`
are now
`en-US`
in order for i18n formatter to work correctly (samdark)
-
Chg #3687: Default
`sourceLanguage`
and
`language`
are now
`en-US`
in order for i18n formatter to work correctly (samdark)
-
Chg #3804: Added
`fileinfo`
PHP extension to the basic requirement of Yii (Ragazzo)
-
Chg #3804: Added
`fileinfo`
PHP extension to the basic requirement of Yii (Ragazzo)
...
...
framework/UPGRADE.md
View file @
a3e2b94a
...
@@ -161,3 +161,14 @@ new ones save the following code as `convert.php` that should be placed in the s
...
@@ -161,3 +161,14 @@ new ones save the following code as `convert.php` that should be placed in the s
// ...
// ...
];
];
```
```
*
If you are using query caching, you should modify your relevant code as follows, as
`beginCache()`
and
`endCache()`
are
replaced by
`cache()`
:
```php
$db->cache(function ($db) {
// ... SQL queries that need to use query caching
}, $duration, $dependency);
```
framework/db/Command.php
View file @
a3e2b94a
This diff is collapsed.
Click to expand it.
framework/db/Connection.php
View file @
a3e2b94a
...
@@ -204,30 +204,21 @@ class Connection extends Component
...
@@ -204,30 +204,21 @@ class Connection extends Component
* @var boolean whether to enable query caching.
* @var boolean whether to enable query caching.
* Note that in order to enable query caching, a valid cache component as specified
* Note that in order to enable query caching, a valid cache component as specified
* by [[queryCache]] must be enabled and [[enableQueryCache]] must be set true.
* by [[queryCache]] must be enabled and [[enableQueryCache]] must be set true.
*
* Methods [[beginCache()]] and [[endCache()]] can be used as shortcuts to turn on
* and off query caching on the fly.
* @see queryCacheDuration
* @see queryCache
* @see queryCache
* @see queryCacheDependency
* @see cache()
* @see beginCache()
* @see noCache()
* @see endCache()
*/
*/
public
$enableQueryCache
=
false
;
public
$enableQueryCache
=
false
;
/**
/**
* @var integer number of seconds that query results can remain valid in cache.
* @var integer the default number of seconds that query results can remain valid in cache.
* Defaults to 3600, meaning 3600 seconds, or one hour.
* Use 0 to indicate that the cached data will never expire.
* Use 0 to indicate that the cached data will never expire.
* Defaults to 3600, meaning 3600 seconds, or one hour. Use 0 to indicate that the cached data will never expire.
* The value of this property will be used when [[cache()]] is called without a cache duration.
* @see enableQueryCache
* @see enableQueryCache
* @see cache()
*/
*/
public
$queryCacheDuration
=
3600
;
public
$queryCacheDuration
=
3600
;
/**
/**
* @var \yii\caching\Dependency the dependency that will be used when saving query results into cache.
* Defaults to null, meaning no dependency.
* @see enableQueryCache
*/
public
$queryCacheDependency
;
/**
* @var Cache|string the cache object or the ID of the cache application component
* @var Cache|string the cache object or the ID of the cache application component
* that is used for query caching.
* that is used for query caching.
* @see enableQueryCache
* @see enableQueryCache
...
@@ -369,6 +360,10 @@ class Connection extends Component
...
@@ -369,6 +360,10 @@ class Connection extends Component
* @var Connection the currently active slave connection
* @var Connection the currently active slave connection
*/
*/
private
$_slave
=
false
;
private
$_slave
=
false
;
/**
* @var array query cache parameters for the [[cache()]] calls
*/
private
$_queryCacheInfo
=
[];
/**
/**
...
@@ -381,29 +376,98 @@ class Connection extends Component
...
@@ -381,29 +376,98 @@ class Connection extends Component
}
}
/**
/**
* Turns on query caching.
* Uses query cache for the queries performed with the callable.
* This method is provided as a shortcut to setting two properties that are related
* When query caching is enabled ([[enableQueryCache]] is true and [[queryCache]] refers to a valid cache),
* with query caching: [[queryCacheDuration]] and [[queryCacheDependency]].
* queries performed within the callable will be cached and their results will be fetched from cache if available.
* @param integer $duration the number of seconds that query results may remain valid in cache.
* For example,
* If not set, it will use the value of [[queryCacheDuration]]. See [[queryCacheDuration]] for more details.
*
* @param \yii\caching\Dependency $dependency the dependency for the cached query result.
* ```php
* See [[queryCacheDependency]] for more details.
* // The customer will be fetched from cache if available.
* // If not, the query will be made against DB and cached for use next time.
* $customer = $db->cache(function (Connection $db) {
* return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
* });
* ```
*
* Note that query cache is only meaningful for queries that return results. For queries performed with
* [[Command::execute()]], query cache will not be used.
*
* @param callable $callable a PHP callable that contains DB queries which will make use of query cache.
* The signature of the callable is `function (Connection $db)`.
* @param integer $duration the number of seconds that query results can remain valid in the cache. If this is
* not set, the value of [[queryCacheDuration]] will be used instead.
* Use 0 to indicate that the cached data will never expire.
* @param \yii\caching\Dependency $dependency the cache dependency associated with the cached query results.
* @return mixed the return result of the callable
* @see enableQueryCache
* @see queryCache
* @see noCache()
*/
*/
public
function
beginCache
(
$duration
=
null
,
$dependency
=
null
)
public
function
cache
(
callable
$callable
,
$duration
=
null
,
$dependency
=
null
)
{
{
$this
->
enableQueryCache
=
true
;
$this
->
_queryCacheInfo
[]
=
[
$duration
===
null
?
$this
->
queryCacheDuration
:
$duration
,
$dependency
];
if
(
$duration
!==
null
)
{
$result
=
call_user_func
(
$callable
,
$this
);
$this
->
queryCacheDuration
=
$duration
;
array_pop
(
$this
->
_queryCacheInfo
);
return
$result
;
}
/**
* Disables query cache temporarily.
* Queries performed within the callable will not use query cache at all. For example,
*
* ```php
* $db->cache(function (Connection $db) {
*
* // ... queries that use query cache ...
*
* return $db->noCache(function (Connection $db) {
* // this query will not use query cache
* return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
* });
* });
* ```
*
* @param callable $callable a PHP callable that contains DB queries which should not use query cache.
* The signature of the callable is `function (Connection $db)`.
* @return mixed the return result of the callable
* @see enableQueryCache
* @see queryCache
* @see cache()
*/
public
function
noCache
(
callable
$callable
)
{
$this
->
_queryCacheInfo
[]
=
false
;
$result
=
call_user_func
(
$callable
,
$this
);
array_pop
(
$this
->
_queryCacheInfo
);
return
$result
;
}
/**
* Returns the current query cache information.
* This method is used internally by [[Command]].
* @return array the current query cache information, or null if query cache is not enabled.
* @internal
*/
public
function
getQueryCacheInfo
()
{
$info
=
end
(
$this
->
_queryCacheInfo
);
if
(
$this
->
enableQueryCache
)
{
$cache
=
$this
->
queryCache
instanceof
Cache
?
$this
->
queryCache
:
Yii
::
$app
->
get
(
$this
->
queryCache
,
false
);
if
(
$cache
instanceof
Cache
)
{
return
is_array
(
$info
)
?
[
$cache
,
$info
[
0
],
$info
[
1
]]
:
[
$cache
,
null
,
null
];
}
}
}
$this
->
queryCacheDependency
=
$dependency
;
return
null
;
}
}
/**
/**
* Turns off query caching.
* Cleans up the query cache information.
* This method is used internally by [[Command]].
* @internal
*/
*/
public
function
endCache
()
public
function
resetQueryCacheInfo
()
{
{
$this
->
enableQueryCache
=
false
;
$this
->
_queryCacheInfo
=
[]
;
}
}
/**
/**
...
...
tests/unit/framework/db/CommandTest.php
View file @
a3e2b94a
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
namespace
yiiunit\framework\db
;
namespace
yiiunit\framework\db
;
use
yii\caching\FileCache
;
use
yii\db\Connection
;
use
yii\db\DataReader
;
use
yii\db\DataReader
;
/**
/**
...
@@ -240,6 +242,7 @@ class CommandTest extends DatabaseTestCase
...
@@ -240,6 +242,7 @@ class CommandTest extends DatabaseTestCase
$this
->
assertEquals
(
2
,
$command
->
execute
());
$this
->
assertEquals
(
2
,
$command
->
execute
());
}
}
/*
public function testInsert()
public function testInsert()
{
{
}
}
...
@@ -299,6 +302,7 @@ class CommandTest extends DatabaseTestCase
...
@@ -299,6 +302,7 @@ class CommandTest extends DatabaseTestCase
public function testDropIndex()
public function testDropIndex()
{
{
}
}
*/
public
function
testIntegrityViolation
()
public
function
testIntegrityViolation
()
{
{
...
@@ -311,4 +315,49 @@ class CommandTest extends DatabaseTestCase
...
@@ -311,4 +315,49 @@ class CommandTest extends DatabaseTestCase
$command
->
execute
();
$command
->
execute
();
$command
->
execute
();
$command
->
execute
();
}
}
public
function
testQueryCache
()
{
$db
=
$this
->
getConnection
();
$db
->
enableQueryCache
=
true
;
$db
->
queryCache
=
new
FileCache
([
'cachePath'
=>
'@yiiunit/runtime/cache'
]);
$command
=
$db
->
createCommand
(
'SELECT name FROM customer WHERE id=:id'
);
$this
->
assertEquals
(
'user1'
,
$command
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
$update
=
$db
->
createCommand
(
'UPDATE customer SET name=:name WHERE id=:id'
);
$update
->
bindValues
([
':id'
=>
1
,
':name'
=>
'user11'
])
->
execute
();
$this
->
assertEquals
(
'user11'
,
$command
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
$db
->
cache
(
function
(
Connection
$db
)
use
(
$command
,
$update
)
{
$this
->
assertEquals
(
'user2'
,
$command
->
bindValue
(
':id'
,
2
)
->
queryScalar
());
$update
->
bindValues
([
':id'
=>
2
,
':name'
=>
'user22'
])
->
execute
();
$this
->
assertEquals
(
'user2'
,
$command
->
bindValue
(
':id'
,
2
)
->
queryScalar
());
$db
->
noCache
(
function
()
use
(
$command
)
{
$this
->
assertEquals
(
'user22'
,
$command
->
bindValue
(
':id'
,
2
)
->
queryScalar
());
});
$this
->
assertEquals
(
'user2'
,
$command
->
bindValue
(
':id'
,
2
)
->
queryScalar
());
},
10
);
$db
->
enableQueryCache
=
false
;
$db
->
cache
(
function
(
$db
)
use
(
$command
,
$update
)
{
$this
->
assertEquals
(
'user22'
,
$command
->
bindValue
(
':id'
,
2
)
->
queryScalar
());
$update
->
bindValues
([
':id'
=>
2
,
':name'
=>
'user2'
])
->
execute
();
$this
->
assertEquals
(
'user2'
,
$command
->
bindValue
(
':id'
,
2
)
->
queryScalar
());
},
10
);
$db
->
enableQueryCache
=
true
;
$command
=
$db
->
createCommand
(
'SELECT name FROM customer WHERE id=:id'
)
->
cache
();
$this
->
assertEquals
(
'user11'
,
$command
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
$update
->
bindValues
([
':id'
=>
1
,
':name'
=>
'user1'
])
->
execute
();
$this
->
assertEquals
(
'user11'
,
$command
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
$this
->
assertEquals
(
'user1'
,
$command
->
noCache
()
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
$command
=
$db
->
createCommand
(
'SELECT name FROM customer WHERE id=:id'
);
$db
->
cache
(
function
(
Connection
$db
)
use
(
$command
,
$update
)
{
$this
->
assertEquals
(
'user11'
,
$command
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
$this
->
assertEquals
(
'user1'
,
$command
->
noCache
()
->
bindValue
(
':id'
,
1
)
->
queryScalar
());
},
10
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment