数据库事务实验 (ISOLATION_DEFAULT)

ISOLATION_DEFAULT: Use the default isolation level of the underlying datastore.

The default isolation level in MySQL’s InnoDB is REPEATABLE READ.

实验一

  • @transaction标签在class上
  • mapper xml没有配置flushCache以及useCache
  • 初始表数据为空

先执行insert20次,每次休眠1秒

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行select30次,每次休眠1秒

    List<WechatUser> wechatUser = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUser.size());

结果:

2016-03-18 12:49:39 [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource]-[DEBUG] Adding transactional method 'WechatRegistServiceImpl.insertUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

2016-03-18 12:49:39 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Creating new transaction with name [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl.insertUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

2016-03-18 12:49:40 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Acquired Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction

2016-03-18 12:49:40 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Switching JDBC Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] to manual commit

2016-03-18 12:49:40 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Creating a new SqlSession

2016-03-18 12:49:40 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353]

2016-03-18 12:49:40 [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] will be managed by Spring

2016-03-18 12:49:40 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Preparing: insert into WECHAT_USER (open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date) values (?, ?, 1, ?, "system", now(), "system", now())

2016-03-18 12:49:40 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Parameters: 1234567890(String), insert(String), null

2016-03-18 12:49:40 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] <== Updates: 1

2016-03-18 12:49:40 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353]

2016-03-18 12:49:40 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 0 条

2016-03-18 12:49:41 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353] from current transaction

2016-03-18 12:49:41 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Preparing: insert into WECHAT_USER (open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date) values (?, ?, 1, ?, "system", now(), "system", now())

2016-03-18 12:49:41 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Parameters: 1234567890(String), insert(String), null

2016-03-18 12:49:41 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] <== Updates: 1

2016-03-18 12:49:41 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession
[org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353]
2016-03-18 12:49:41 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 1 条

...

2016-03-18 12:49:43 [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /select.html

2016-03-18 12:49:43 [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource]-[DEBUG] Adding transactional method 'WechatRegistServiceImpl.selectUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

2016-03-18 12:49:43 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Creating new transaction with name [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl.selectUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

2016-03-18 12:49:43 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Acquired Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction

2016-03-18 12:49:43 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Switching JDBC Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] to manual commit

2016-03-18 12:49:43 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Creating a new SqlSession

2016-03-18 12:49:43 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d]

2016-03-18 12:49:43 [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] will be managed by Spring

2016-03-18 12:49:43 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Preparing: select user_id, open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date from WECHAT_USER

2016-03-18 12:49:43 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Parameters:

2016-03-18 12:49:43 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] <== Total: 0

2016-03-18 12:49:43 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession
[org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d]

2016-03-18 12:49:43 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:0 用户数量:0

2016-03-18 12:49:44 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353] from current transaction

2016-03-18 12:49:44 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Preparing: insert into WECHAT_USER (open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date) values (?, ?, 1, ?, "system", now(), "system", now())

...

2016-03-18 12:49:44 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d] from current transaction

2016-03-18 12:49:44 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d]

2016-03-18 12:49:44 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:1 用户数量:0

...

2016-03-18 12:50:00 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353]

2016-03-18 12:50:00 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353]

2016-03-18 12:50:00 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@21e3b353]

2016-03-18 12:50:00 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Initiating transaction commit

2016-03-18 12:50:00 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver]

2016-03-18 12:50:00 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Releasing JDBC Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction

2016-03-18 12:50:00 [org.springframework.jdbc.datasource.DataSourceUtils]-[DEBUG] Returning JDBC Connection to DataSource

2016-03-18 12:50:11 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d] from current transaction

2016-03-18 12:50:11 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d]

2016-03-18 12:50:11 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:28 用户数量:0

2016-03-18 12:50:12 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d] from current transaction

2016-03-18 12:50:12 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a50701d]

2016-03-18 12:50:12 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:29 用户数量:0

再发一次select请求

...

2016-03-18 12:59:34 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Preparing: select user_id, open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date from WECHAT_USER
2016-03-18 12:59:34 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Parameters:
2016-03-18 12:59:34 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] == Total: 20
2016-03-18 12:59:34 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75ab43b7]
2016-03-18 12:59:34 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:0 用户数量:20
2016-03-18 12:59:35 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75ab43b7] from current transaction
2016-03-18 12:59:35 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75ab43b7]
2016-03-18 12:59:35 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:1 用户数量:20
2016-03-18 12:59:36 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75ab43b7] from current transaction
2016-03-18 12:59:36 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75ab43b7]
2016-03-18 12:59:36 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:2 用户数量:20

结论

  • 读在一个事务中读的都是缓存,一个事务进行中没有新的请求过去
  • 事务的状态是:PROPAGATION_REQUIRED,ISOLATION_DEFAULT
  • 先是Creating a new SqlSession,然后Releasing transactional SqlSession,再有请求则是Fetched SqlSession from current transaction
  • 读事务中第一次读,拿到的数据是写事务进行之前数据库的状态;之后拿到的数据都是在缓存中拿到的,无论写事务状态是什么

实验二

  • @transaction标签在class上
  • mapper xml没有配置flushCache以及useCache

先执行insert20次,每次休眠1秒(同一个insert方法)

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行insert20次,每次休眠1秒(同一个insert方法)

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

结果:

2016-03-18 13:16:56 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Preparing: insert into WECHAT_USER (open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date) values (?, ?, 1, ?, "system", now(), "system", now())
2016-03-18 13:16:56 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Parameters: 1234567890(String), insert(String), null
2016-03-18 13:16:56 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] == Updates: 1
2016-03-18 13:16:56 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3cb57f97]
2016-03-18 13:16:56 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 1 条
2016-03-18 13:16:57 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@302693e9] from current transaction
2016-03-18 13:16:57 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Preparing: insert into WECHAT_USER (open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date) values (?, ?, 1, ?, "system", now(), "system", now())
2016-03-18 13:16:57 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Parameters: 1234567890(String), insert(String), null
2016-03-18 13:16:57 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] == Updates: 1
2016-03-18 13:16:57 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@302693e9]
2016-03-18 13:16:57 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 8 条

结论

  • 两次写事务并行进行

实验三

  • @transaction标签在方法上
  • mapper xml没有配置flushCache以及useCache
  • 初始表数据为空

先执行insert20次,每次休眠1秒

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行select30次,每次休眠1秒

    List<WechatUser> wechatUser = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUser.size());

结果:

同实验一


实验四

  • @transaction标签在方法上
  • mapper xml没有配置flushCache以及useCache

先执行insert20次,每次休眠1秒

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行insert20次,每次休眠1秒

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

结果:

同实验二


实验五

  • @transaction标签在方法上
  • mapper xml设置flushCache="true" useCache="false"
    <select id="select" resultMap="BaseResultMap" parameterType="java.lang.String" flushCache="true" useCache="false">
  • 初始表数据为空

先执行insert20次,每次休眠1秒

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行select30次,每次休眠1秒

    List<WechatUser> wechatUser = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUser.size());

结果:

2016-03-18 13:49:37 [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource]-[DEBUG] Adding transactional method 'WechatRegistServiceImpl.insertUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2016-03-18 13:49:37 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Creating new transaction with name [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl.insertUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2016-03-18 13:49:38 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Acquired Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction

...

2016-03-18 13:49:38 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Preparing: insert into WECHAT_USER (open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date) values (?, ?, 1, ?, "system", now(), "system", now())

2016-03-18 13:49:38 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] ==> Parameters: 1234567890(String), insert(String), null

2016-03-18 13:49:38 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.insert]-[DEBUG] <== Updates: 1

2016-03-18 13:49:38 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e6ab308]

2016-03-18 13:49:38 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 0 条

...

2016-03-18 13:49:39 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 1 条

...

2016-03-18 13:49:40 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 2 条

2016-03-18 13:49:40 [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /select.html

2016-03-18 13:49:40 [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource]-[DEBUG] Adding transactional method 'WechatRegistServiceImpl.selectUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

...

2016-03-18 13:49:40 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Preparing: select user_id, open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date from WECHAT_USER

...

2016-03-18 13:49:40 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:0 用户数量:0

...

2016-03-18 13:49:41 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Preparing: select user_id, open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date from WECHAT_USER

...

2016-03-18 13:49:41 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:1 用户数量:0

...

2016-03-18 13:50:08 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Preparing: select user_id, open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date from WECHAT_USER

2016-03-18 13:50:08 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:28 用户数量:0

2016-03-18 13:50:09 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.select]-[DEBUG] ==> Preparing: select user_id, open_id, user_name, use_yn, authority_value, insert_id, insert_date, modify_id, modify_date from WECHAT_USER

2016-03-18 13:50:09 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:29 用户数量:0

结论

  • 读事务中第一次读,拿到的数据是写事务进行之前数据库的状态

实验六

  • @transaction标签在方法上

先执行update20次,每次休眠1秒(update同一条数据)

    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

再执行update20次,每次休眠1秒(update同一条数据)

    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

结果:

2016-03-18 14:50:30 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.update]-[DEBUG] ==> Preparing: update WECHAT_USER SET open_id = ?, user_name = ?, modify_date = now() where open_id = "abc"

2016-03-18 14:50:30 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------修改数据:0 结果1

2016-03-18 14:50:31 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@77e2cc94] from current transaction

2016-03-18 14:50:31 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.update]-[DEBUG] ==> Preparing: update WECHAT_USER SET open_id = ?, user_name = ?, modify_date = now() where open_id = "abc"

2016-03-18 14:50:31 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------修改数据:1 结果0

2016-03-18 14:50:32 [org.springframework.web.servlet.DispatcherServlet]-[DEBUG] DispatcherServlet with name 'spring' processing GET request for [/springtest/update.html]

2016-03-18 14:50:32 [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /update.html

...

2016-03-18 14:50:32 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.update]-[DEBUG] ==> Preparing: update WECHAT_USER SET open_id = ?, user_name = ?, modify_date = now() where open_id = "abc"

2016-03-18 14:50:32 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------修改数据:2 结果0

...

2016-03-18 14:50:49 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------修改数据:19 结果0

2016-03-18 14:50:50 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@77e2cc94]

2016-03-18 14:50:50 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@77e2cc94]

2016-03-18 14:50:50 [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@77e2cc94]

2016-03-18 14:50:50 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Initiating transaction commit

2016-03-18 14:50:50 [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sip?useUnicode=yes&characterEncoding=UTF8, UserName=root@localhost, MySQL-AB JDBC Driver]

...

2016-03-18 14:50:50 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------修改数据:0 结果0

...

2016-03-18 14:50:51 [cn.hao24.mobauto.mapper.wechatusers.WechatUserMapper.update]-[DEBUG] ==> Preparing: update WECHAT_USER SET open_id = ?, user_name = ?, modify_date = now() where open_id = "abc"

2016-03-18 14:50:51 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------修改数据:1 结果0

结论

  • 当两个写事务都是操作同一个数据的时候,第二个写事务会等第一个写事务提交之后才会进行

实验七

  • @transaction标签在方法上

先执行update20次,每次休眠1秒(update不同一条数据)

    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

再执行update20次,每次休眠1秒(update不同一条数据)

    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

结果:

同实验六


实验八

  • @transaction标签在方法上

先执行update20次,每次休眠1秒

    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

再执行insert20次,每次休眠1秒

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

结果:

先执行updateupdate事务结束后,执行insert


实验九

  • @transaction标签在class

先执行insert20次,每次休眠1秒(不同insert方法)

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行insert20次,每次休眠1秒(不同insert方法)

    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

结果:

并行


实验十

  • @transaction标签在方法上
  • mapper xml设置flushCache="true" useCache="false"
    <select id="select" resultMap="BaseResultMap" parameterType="java.lang.String" flushCache="true" useCache="false">

先执行select + insert20次,每次休眠1秒(同一个select + insert方法)

    List<WechatUser> wechatUserList = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUserList.size());
    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

再执行select + insert20次,每次休眠1秒(同一个select + insert方法)

    List<WechatUser> wechatUserList = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUserList.size());
    wechatUserMapper.insert(wechatUser);
    logger.info("----------------写入数据第   " + i + " 条");

结果:

2016-03-18 16:17:43 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:5 用户数量:5

...

2016-03-18 16:17:43 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 5 条

...

2016-03-18 16:17:44 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:0 用户数量:0

...

2016-03-18 16:17:44 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 0 条

...

2016-03-18 16:17:44 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:6 用户数量:6

...

2016-03-18 16:17:44 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 6 条

...

2016-03-18 16:17:45 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:1 用户数量:1

...

2016-03-18 16:17:58 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:19 用户数量:19

...

2016-03-18 16:17:58 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 19 条

...

2016-03-18 16:17:58 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------读出数据:14 用户数量:14

...

2016-03-18 16:17:58 [cn.hao24.mobauto.db.service.wechatuser.impl.WechatRegistServiceImpl]-[INFO] ----------------写入数据第 14 条

结论

  • 两个读写事务或并行运行;但是他们对数据库的影响不会作用到彼此,即大家读的都是快照

实验十一

  • @transaction标签在方法上
  • mapper xml设置flushCache="true" useCache="false"
    <select id="select" resultMap="BaseResultMap" parameterType="java.lang.String" flushCache="true" useCache="false">

先执行select + update20次,每次休眠1秒(同一个select + update方法)

    List<WechatUser> wechatUserList = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUserList.size());
    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

再执行select + update20次,每次休眠1秒(同一个select + update方法)

    List<WechatUser> wechatUserList = wechatUserMapper.select();
    logger.info("----------------读出数据:" + i + "    用户数量:" + wechatUserList.size());
    int result = wechatUserMapper.update(wechatUser);
    logger.info("----------------修改数据:" + i + "  结果" + result);

结果:

两次大事务串行

2016/3/18 posted in  数据库

Why use Paxos?

Paxos is a protocol for state machine replication in an asynchronous environment that admits crash failures.

A replicated state machine works by having multiple state machines, also called replicas, working in parallel, maintaining the same state. When the replicas receive requests from a client they update their state by executing the command in the request and reply to the client. This way, the state is automatically replicated by the replicas and in the event of a failure the state does not get lost, making the replicated state machine reliable.

It is easy for replicas to execute client commands in the same order and remain in sync if there is only one client or if multiple clients send their requests strictly sequentially.

But if multiple clients send requests to replicas in parallel, then different replicas might receive these requests in different orders and execute the commands in different orders, causing their local states to diverge from one another over time.

To prevent replicas from diverging in the presence of multiple clients sending requests in parallel, the order in which the client commands will be executed by replicas should be decided.

To decide the order in which the client commands will be executed the replicas can be thought of as having a sequence of slots that need to be filled with commands that make up the inputs to the state machine they maintain.

In the example this sequence is shown as a table. Each slot is indexed by a slot number, starting from 1. Replicas receive requests from clients and assign them to specific slots, creating a sequence of commands.

In the face of concurrently operating clients, different replicas may end up proposing different commands for the same slot. To avoid inconsistency, a consensus protocol chooses a single command from the proposals for every slot.

In Paxos the subprotocol that implements consensus is called the multi-decree Synod protocol, or just Synod protocol for short. A replica awaits the decision before actually updating its sequence of commands in the table, executing the next command and computing a response to send back to the client that issued the request.

Essentially. the replicated state machine uses Paxos as an ordering entity which uses consensus to agree on which client command gets assigned to which slot. One has to make sure that the ordering entity itself is also reliable, that it can tolerate failure just like the replicaed state machine.

To achieve reliability, Paxos is run by multiple specialized processes in a distributed fashion. This is not trivial because up to f processes running Paxos might fail at any time and, because there is no bound on timing for delivering and processing messages, it is impossible for other processes to know for certain that the process has failed.

2016/3/16 posted in  PAXOS

`Memcached`解读

Memcached实现原理

Memcached将数据存放在内存中,有这么几个特点:

  • 访问速度比传统关系型数据库要快
  • 只要Memcached重启了,数据也就丢失了

Memcached采用的内存分配方式是固定空间分配

  • Memcached将内存空间分成一组slab
  • 每个slab下有若干个page,每个page默认是1MB,如果一个slab占用100MB内存的话,那么这个slab下就有100个page
  • 每个page里面包含一组chunkchunk是真正存放数据的地方,同一个slab里面的chunk的大小是固定的
  • 有相同大小的chunkslab被组织在一起,称为slab_class

Memcached有新的value进来,它的存放位置是由value的大小决定的,value总是被存放到与chunk大小最接近的那个slab

slab的时候,首先slab要申请内存,申请内存是以page为单位的,所以在放入第一个数据的时候,无论大小为多少,都会有1MB大小的page被分配给该slab。申请到page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成一个chunk数组。

相邻slab内的chunk基本以1.25为比例的增长

Memcached内存分配和回收算法,有三点要注意:

  • Memcached内存分配时,chunk里面会有内存浪费,88字节的value分配在128字节的chunk中,就损失了30个字节,但是避免了管理内存碎片的问题
  • MemcachedLRU算法不是针对全局的,而是针对slab
  • value的大小不能大于1MB,因为page只有1MB
2016/3/15 posted in  others

MyBatis缓存机制

关于Mybatis

MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和JavaPOJOPlain Old Java Objects,普通的Java对象)映射成数据库中的记录。

一、为什么需要缓存

提高对数据库查询的效率,提高应用的性能。

二、MyBatis缓存机制整体设计

MyBatis缓存分为一级和二级,使用顺序:

二级缓存 —> 一级缓存 —> 数据库

三、MyBatis 一级缓存

1、什么是一级缓存

对于会话(Session)级别的数据缓存,称之为一级缓存。

2、一级缓存的生命周期

  • MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象, SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的 PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
  • 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
  • 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
  • SqlSession中执行了任何一个update操作(update()delete()insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;

3、一级缓存工作流程

  • 对于某个查询,根据statementId, params, rowBounds来构建一个key,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;
  • 判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;
  • 如果命中,则直接将缓存结果返回;
  • 如果没命中:

    • 去数据库中查询数据,得到查询结果;
    • 将key和查询到的结果分别作为key, value对存储到Cache中;
    • 将查询结果返回;
  • 结束。

4、一级缓存性能分析

  • MyBatis对会话(Session)级别的一级缓存设计的比较简单,就简单地使用了 HashMap来维护,并没有对HashMap的容量和大小进行限制。

  • 一级缓存是一个粗粒度的缓存,没有更新缓存和缓存过期的概念

四、MyBatis二级缓存

1、二级缓存工作模式

当开一个会话时,一个SqlSession对象会使用一个Executor对象来完成会话操作, MyBatis的二级缓存机制的关键就是对这个Executor对象做文章。如果用户配了cacheEnabled=true,那么MyBatis在为SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:CachingExecutor,这时 SqlSession使用CachingExecutor对象来完成操作请求。CachingExecutor对于查询请求,会先判断该查询请求在Application级别的二级缓存中是否有缓存结果,如果有查询结果,则直接返回缓存结果;如果缓存中没有,再交给真正的Executor对象来完成查询操作,之后CachingExecutor会将真正Executor返回的查询结果放置到缓存中,然后在返回给用户。

2、二级缓存划分

MyBatis并不是简单地对整个Application就只有一个Cache缓存对象,它将缓存划分的更细,即是Mapper级别的,即每一个Mapper都可以拥有一个Cache对象,具体如下:

  • 为每一个Mapper分配一个Cache缓存对象(使用 <cache> 节点配置);
  • 多个Mapper共用一个Cache缓存对象(使用 <cache-ref> 节点配置);

要想使某条Select查询支持二级缓存,你需要保证:

  1. MyBatis支持二级缓存的总开关:全局配置变量参数cacheEnabled = true
  2. select语句所在的Mapper,配置了 <cache><cached-ref>节点,并且有效
  3. select语句的参数useCache = true

3、二级缓存生命周期

二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

4、二级缓存禁用与刷新

useCache = "false"可以禁用二级缓存,默认select语句useCache = "true"

flushCache = "false"即不会刷新缓存,默认flushCache = "true"

5、Mybatis Cache参数

lushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。

readOnly(只读)属性可以被设置为truefalse。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

如下例子:

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

这个更高级的配置创建了一个FIFO缓存,并每隔60秒刷新,存数结果对象或列表的512个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是`LRU:

LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

6、二级缓存的局限性

Mybatis的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空,而无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,解决此类问题需要在业务层根据需求对数据有针对性缓存。

2016/3/15 posted in  数据库

RabbitMQ的阻塞和初步优化

RabbitMQ占用内存达到峰值(内存的40%)消息链接就会发生阻塞

情况模拟:大量发送消息,RabbitMQ的消息处于堆积状态,内存值持续增大,RabbitMQ 的连接会阻塞。导致发送等待状态,CPU、内存占用很大,发送消息服务器异常。

异常处理结果分析:

管理后台删除queue会大幅度的减少内存的占用,内存释放,链接不会发生阻塞,接受消息正常,CPU也正常。

异常发生原因初步分析:

1. 消费者采用的排他队列(Exclusive)和持久化方式(Durable

持久化方式消息保存在磁盘中,非持久化保存在内存采用临时队列,应该注意以下三点:

  • 排他队列是基于连接可见的,同一连接的不同信道是可以同时访问同一个连接创建的临时队列的

  • 连接间不允许建立同名的排他队列的

  • 即使该队列是持久化的,一旦连接关闭或者客户端退出,应立即删除队列

我们处理措施:队列修改为一旦连接关闭或者客户端退出,该队列都会被立即删除

channel.queueDeclare(queueName, true, true, true, null);
  • @param queue the name of the queue
  • @param durable true if we are declaring a durable queue (the queue will survive a server restart) 服务器重启
  • @param exclusive true if we are declaring an exclusive queue (restricted to this connection) 一个queue能不能有多个消费者
  • @param autoDelete true if we are declaring an autodelete queue (server will delete it when no longer in use) 如果一个queue的全部消费者都挂了
  • @param arguments other properties (construction arguments) for the queue
  • @return a declaration-confirm method to indicate the queue was successfully declared

2. 修正程序中的bug,建立MQSender时不建Queue

在之前的程序中,当我们新建一个MQSender总会建一个Queue,而这个Queue没有消费者。P在发送信息时总会同时发送给ExchangeQueue。没有消费者以及持续不断地收消息导致Queue占用内存不断增大,最终拖垮整个RabbitMQ的效能。

异常导致RabbitMQ连接异常处理:

1.管理页面可以访问的情况下

点击queues --> 点击对应的队列名 --> 进入队列详情页面,点击页面底部的delete按钮删除相应的队列,上述操作可以让RabbitMQ的内存下降

2.管理后台不能访问,后台不能启动,后台相关处理

删除所有queues的消息,减小内存 (110为例)

cd /var/lib/rabbitmq/mnesia/rabbit\@template-CentOS6/
rm -rf queues

启动RabbitMQ

service rabbitmq-server start

此时两种方式删除queues

1.访问管理台页面按1的方式删除queues
2.linux管理台删除
rabbitmqctl stop_app 

清除所有队列同时初始化rabbitmq

rabbitmqctl reset

创建登录管理后台的用户用户名 密码

rabbitmqctl add_user 用户名 密码
rabbitmqctl set_user_tags 用户名 administrator
rabbitmqctl set_permissions -p / hao24 ".*" ".*" ".*"

建立连接用户名密码

rabbitmqctl add_user 用户名 密码
rabbitmqctl set_permissions -p / 用户名 ".*" ".*" ".*"
2016/3/15 posted in  RabbitMQ