如何使用PdoSessionHandler把session存储到数据库中
默认的Symfony session存储,是把session信息写入到文件中。多数中到大型网站使用一个数据库来存储session值而是不使用文件,这是因为在“服务器集群”环境下数据库更容易使用和升级。
对于数据库的session存储,Symfony提供一个内置的解决方案叫做
PdoSessionHandler
。为了使用它,你只需在主配置文件中改变一些参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# app/config/config.yml
framework:
session:
# ...
handler_id: session.handler.pdo
services:
session.handler.pdo:
class: Symfony\Component\Httpfoundation\Session\Storage\Handler\PdoSessionHandler
public: false
arguments:
- 'mysql:dbname=mydatabase'
- { db_username: myuser, db_password: mypassword } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- app/config/config.xml -->
<framework:config>
<framework:session handler-id="session.handler.pdo" cookie-lifetime="3600" auto-start="true"/>
</framework:config>
<services>
<service id="session.handler.pdo" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" public="false">
<argument>mysql:dbname=mydatabase</agruement>
<argument type="collection">
<argument key="db_username">myuser</argument>
<argument key="db_password">mypassword</argument>
</argument>
</service>
</services> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$container->loadFromExtension('framework', array(
...,
'session' => array(
// ...,
'handler_id' => 'session.handler.pdo',
),
));
$storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array(
'mysql:dbname=mydatabase',
array('db_username' => 'myuser', 'db_password' => 'mypassword')
));
$container->setDefinition('session.handler.pdo', $storageDefinition); |
配置表名和列名 ¶
这将预期一个sessions
表以及一些不同的列。表名,和所有的列名,都可以被配置,通过向PdoSessionHandler
传入二维数组的参数即可:
1 2 3 4 5 6 7 8 9 |
# app/config/config.yml
services:
# ...
session.handler.pdo:
class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
public: false
arguments:
- 'mysql:dbname=mydatabase'
- { db_table: sessions, db_username: myuser, db_password: mypassword } |
1 2 3 4 5 6 7 8 9 10 11 |
<!-- app/config/config.xml -->
<services>
<service id="session.handler.pdo" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" public="false">
<argument>mysql:dbname=mydatabase</agruement>
<argument type="collection">
<argument key="db_table">sessions</argument>
<argument key="db_username">myuser</argument>
<argument key="db_password">mypassword</argument>
</argument>
</service>
</services> |
1 2 3 4 5 6 7 8 9 10 |
// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;
// ...
$storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array(
'mysql:dbname=mydatabase',
array('db_table' => 'sessions', 'db_username' => 'myuser', 'db_password' => 'mypassword')
));
$container->setDefinition('session.handler.pdo', $storageDefinition); |
以下是你必须要配置的参数(键):
db_talbe
(默认是sessions
):
你的数据库session表的名字;
db_id_col
(默认是sess_id
):
你的session表的id字段的名字(VARCHAR(128));
db_data_col
(默认是sess_data
):
你的session表的value字段的名字(BLOB);
db_time_col
(默认是sess_time
):
你的session表的字段的名字(INTEGER);
db_lifetime_col
(默认是sess_lifetime
):
你的session表的lifetime字段的名字(INTEGER);
分享你的数据库连接信息 ¶
根据给出的配置,数据库的连接设置(database connection settings)仅能被定义为session storage连接。这在当你使用一个用于session数据的独立数据库时是没有问题的。
但如果你希望把session数据存到“与你的项目数据所在”相同的数据库的话,你可以使用parameters.yml
中的连接信息,通过引用定义在那里的database相关参数即可:
1 2 3 4 5 6 7 |
services:
session.handler.pdo:
class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
public: false
arguments:
- 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%'
- { db_username: '%database_user%', db_password: '%database_password%' } |
1 2 3 4 5 6 7 |
<service id="session.handler.pdo" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" public="false">
<argument>mysql:host=%database_host%;port=%database_port%;dbname=%database_name%</argument>
<argument type="collection">
<argument key="db_username">%database_user%</argument>
<argument key="db_password">%database_password%</argument>
</argument>
</service> |
1 2 3 4 |
$storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array(
'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%',
array('db_username' => '%database_user%', 'db_password' => '%database_password%')
)); |
准备数据库以存储Session ¶
在把session存入数据库之前,你必须创建用来存放信息的表。下面小节包含了一些SQL声明的样例,你可以用在自己特定的数据库引擎中。
MySQL ¶
1 2 3 4 5 6 |
CREATE TABLE `sessions` (
`sess_id` VARBINARY(128) NOT NULL PRIMARY KEY,
`sess_data` BLOB NOT NULL,
`sess_time` INTEGER UNSIGNED NOT NULL,
`sess_lifetime` MEDIUMINT NOT NULL
) COLLATE utf8_bin, ENGINE = innodb; |
BLOB
字段类型只能存放64kb的内容。如果存于用户session中的数据超出此值,会有异常抛出,或者用户的session会被静默重置。如果有容量需求可以考虑使用MEDIUMBLOG
字段。
postgresql ¶
1 2 3 4 5 |
CREATE TABLE sessions (
sess_id VARCHAR(128) NOT NULL PRIMARY KEY,
sess_data BYTEA NOT NULL,
sess_time INTEGER NOT NULL,
sess_lifetime INTEGER NOT NULL |
Microsoft SQL Server ¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
CREATE TABLE [dbo].[sessions](
[sess_id] [nvarchar](255) NOT NULL,
[sess_data] [ntext] NOT NULL,
[sess_time] [INT] NOT NULL,
[sess_lifetime] [INT] NOT NULL,
PRIMARY KEY CLUSTERED(
[sess_id] ASC
) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] |
如果session数据不适合存入data字段,它可能会被数据库引擎给清除。更糟的是,当session数据挂掉之后,PHP引擎直接忽略数据而不给予警告。
如果程序存储了大量的session data,这个问题可以靠“提升字段容量(使用BLOB
或MEDIUMBLOG
)”来解决。当使用MySQL作为数据库引擎时,你可以同时开启strict SQL mode(严格SQL模式),以便在类似错误发生时,能够收到通知。