设为首页 收藏本站
查看: 1237|回复: 0

[经验分享] SpringMVC+Mybatis声明式事务分析

[复制链接]

尚未签到

发表于 2016-11-26 05:30:13 | 显示全部楼层 |阅读模式
由于本人最近刚刚开始使用SpringMVC+Mybatis,遇到了一个问题:
 
执行查询http://localhost:8080/zcrm/query
 
 
后台日志
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@254ed667]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@254ed667] will not be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@345dbcb5] was not registered for synchronization because synchronization is not active
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: SELECT a.* FROM CRM_USER a WHERE a.username = ? AND a.password = ? 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: canon(String), canon(String)
DEBUG: [java.sql.ResultSet.(28)debug] - <==    Columns: ID, USERNAME, PASSWORD, NICKNAME, CREATE_DATE, STATE, REMARKS
DEBUG: [java.sql.ResultSet.(28)debug] - <==        Row: 1, canon, canon, 卡农, 2015-04-28 00:00:00.0, U, null
DEBUG: [com.alibaba.druid.pool.PreparedStatementPool.(123)put] - {conn-10001, pstmt-20000} enter cache
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Closing no transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@345dbcb5]
 
执行查询http://localhost:8080/zcrm/add?id=334455
 
 
后台日志

DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@254ed667]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@254ed667] will not be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d233a8e] was not registered for synchronization because synchronization is not active
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: insert into CRM_USER (ID, USERNAME, PASSWORD, NICKNAME, CREATE_DATE, STATE, REMARKS) values (?, ?, ?, ?, ?, ?, ?) 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: 334455(Long), null, null, null, null, null, null
DEBUG: [com.alibaba.druid.pool.PreparedStatementPool.(123)put] - {conn-10001, pstmt-20001} enter cache
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Closing no transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d233a8e]
 
问题1:数据库中有没有插入数据呢?
数据库中插入了数据,这点我也没有想明白?
 
危险点(1):context:component-scan设置全局扫描
修改点:
 
  注意web.xml的执行顺序 context-param -> listener -> filter -> servlet 
个人认为Spring也恰巧利用了这一点,利用listener先去加载service层的bean,然后为controller加载成bean提供依赖注入。
这也是Spring设计完美的地点
 
通过【org.springframework.web.context.ContextLoaderListener】扫描对应路径下的@Service等注解的

<context:component-scan base-package="com.zcrm.service" />

 
通过【org.springframework.web.servlet.DispatcherServlet】执行Controller注入
 <!-- controller包自动注入 -->
 <context:component-scan base-package="com.zcrm.controller" >
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
 </context:component-scan>
 
危险点(2):拦截器方式配置事务,容易配置错误
(2-1):expression="execution(* *..*SVImpl.*(..))" 的使用
第一个【*】:任意返回值类型
第二个【*】:任意包名

第一个【..】:通配包路径 可以有0个或者多个包路径
第三个【*】:任意字符+SVImpl的class
第四个【*】:任意方法名

第二个【..】:通配方法可以有0个或者多个参数

 
(2-2):事务的传播级别
1、PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启。
2、PROPAGATION_SUPPORTS如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
3、PROPAGATION_MANDATORY如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4、PROPAGATION_REQUIRES_NEW总是开启一个新的事务。如果一个事务存在,则将这个存在的事务挂起。
5、PROPAGATION_NOT_SUPPORTED总是非事务地执行,并挂起任何存在的事务。
6、PROPAGATION_NEVER总是非事务地执行,如果存在一个活动事务,则抛出异常。
7、 PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按TransactionDefinition.PROPAGATION_REQUIRED属性执行

 
 
 <!-- 拦截器方式配置事务 -->
 <!-- 配置事务传播级别 -->
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
   <tx:method name="save*" propagation="REQUIRED" />
   <tx:method name="add*" propagation="REQUIRED" />
   <tx:method name="create*" propagation="REQUIRED" />
   <tx:method name="insert*" propagation="REQUIRED" />
   <tx:method name="update*" propagation="REQUIRED" />
   <tx:method name="merge*" propagation="REQUIRED" />
   <tx:method name="del*" propagation="REQUIRED" />
   <tx:method name="remove*" propagation="REQUIRED" />
   <tx:method name="put*" propagation="REQUIRED" />
   <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
   <tx:method name="count*" propagation="SUPPORTS" read-only="true" />
   <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
   <tx:method name="list*" propagation="SUPPORTS" read-only="true" />
   <tx:method name="*" propagation="SUPPORTS" read-only="true" />
  </tx:attributes>
 </tx:advice>  
 
 <aop:config>
  <!-- 只对业务逻辑层实施事务 -->
  <aop:pointcut id="txPointcut"
   expression="execution(* *..*SVImpl.*(..))" />
   
  <!-- Advisor定义,切入点和通知分别为txPointcut、txAdvice -->
  <aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice" />
 </aop:config>
 
 
http://blog.csdn.net/wubai250/article/details/8102194
在这里特别感谢【开涛】:http://jinnianshilongnian.iyunv.com/
 
修改后的效果:
 
执行查询http://localhost:8080/zcrm/add?id=334455
 
后台日志
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2b399081]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2b399081] will be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e6dbc7f]
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: insert into CRM_USER (ID, USERNAME, PASSWORD, NICKNAME, CREATE_DATE, STATE, REMARKS) values (?, ?, ?, ?, ?, ?, ?) 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: 2(Long), null, null, null, null, null, null
DEBUG: [com.alibaba.druid.pool.PreparedStatementPool.(123)put] - {conn-10001, pstmt-20000} enter cache
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e6dbc7f]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e6dbc7f]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e6dbc7f]
 
执行查询http://localhost:8080/zcrm/query
 
 
后台日志:关闭SqlSession,但是没有事务的提交
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2b399081]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2b399081] will be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3cc472f2]
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: SELECT a.* FROM CRM_USER a WHERE a.username = ? AND a.password = ? 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: canon(String), canon(String)
DEBUG: [com.alibaba.druid.pool.PreparedStatementPool.(123)put] - {conn-10001, pstmt-20001} enter cache
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3cc472f2]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3cc472f2]
 
 
问题2:为什么这个地方还会开启事务?
求大神解决
 
 
 
 
 
 
实践(1):测试事务回滚
   
      @RequestMapping(value={"/test"},method=RequestMethod.GET)
    public String test(BOCrmUser BOCrmUser) {
     String flag = "error";
     try {
      IUserSV.deleteByPrimaryKey(1l);//id=1
      IUserSV.insert(BOCrmUser);//id=2 2已经存在了,会爆主键重复的异常
             //问题:1的数据有没有被删除
      flag = "success";
  } catch (Exception e) {
   e.printStackTrace();
  }
     return flag;
    }
 
 

  结果:1的数据被删除了,因为删除的操作和新增的操作不再一个事务中
日志:
注意SqlSession
新增的时候SqlSession是[org.apache.ibatis.session.defaults.DefaultSqlSession@5751de43]
删除的时候SqlSession是[org.apache.ibatis.session.defaults.DefaultSqlSession@474c8cd6]
 
注意事务提交
新增的时候,连接打开,事务提交
删除的时候,连接打开,事务没有提交
 
 
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e5d464f]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e5d464f] will be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5751de43]
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: delete from CRM_USER where ID = ? 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: 1(Long)
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5751de43]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5751de43]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5751de43]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e5d464f]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e5d464f] will be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@474c8cd6]
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: insert into CRM_USER (ID, USERNAME, PASSWORD, NICKNAME, CREATE_DATE, STATE, REMARKS) values (?, ?, ?, ?, ?, ?, ?) 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: 2(Long), null, null, null, null, null, null
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@474c8cd6]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@474c8cd6]
org.springframework.dao.DuplicateKeyException: 
### Error updating database.  Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 违反唯一约束条件 (ZCRM.PK_CRM_USER)
 
 

实践(2):将删除(REQUIRED)和新增(REQUIRED)封装到一个新方法update(





REQUIRED)中






















 public void update(BOCrmUser record){
  this.deleteByPrimaryKey(1l);//删除id=1
  this.insert(record);//新增id=2,主键冲突
 }  
 
    @RequestMapping(value={"/update"},method=RequestMethod.GET)
    public String update(BOCrmUser BOCrmUser) {
     String flag = "error";
     try {
      IUserSV.update(BOCrmUser);
      flag = "success";
  } catch (Exception e) {
   e.printStackTrace();
  }
     return flag;
    }
结果(2):1的数据没有被删除,事务回滚













 
 
日志(2)



DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Creating SqlSession with JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e5d464f]
DEBUG: [java.sql.Connection.(28)debug] - ooo Connection Opened
DEBUG: [org.mybatis.spring.transaction.SpringManagedTransaction.(28)debug] - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e5d464f] will be managed by Spring
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b57358d]
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: delete from CRM_USER where ID = ? 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: 1(Long)
DEBUG: [com.alibaba.druid.pool.PreparedStatementPool.(123)put] - {conn-10001, pstmt-20000} enter cache
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b57358d]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b57358d] from current transaction
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==>  Executing: insert into CRM_USER (ID, USERNAME, PASSWORD, NICKNAME, CREATE_DATE, STATE, REMARKS) values (?, ?, ?, ?, ?, ?, ?) 
DEBUG: [java.sql.PreparedStatement.(28)debug] - ==> Parameters: 2(Long), null, null, null, null, null, null
DEBUG: [com.alibaba.druid.pool.PreparedStatementPool.(123)put] - {conn-10001, pstmt-20001} enter cache
INFO : [org.springframework.beans.factory.xml.XmlBeanDefinitionReader.(315)loadBeanDefinitions] - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
INFO : [org.springframework.jdbc.support.SQLErrorCodesFactory.(126)<init>] - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b57358d]
DEBUG: [org.mybatis.spring.SqlSessionUtils.(28)debug] - Transaction synchronization closing SqlSession 
 
事务同步关闭SqlSession
 
[org.apache.ibatis.session.defaults.DefaultSqlSession@5b57358d]
org.springframework.dao.DuplicateKeyException: 
### Error updating database.  Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 违反唯一约束条件 (ZCRM.PK_CRM_USER)

### The error may involve com.zcrm.dao.BOCrmUserMapper.insert-Inline
### The error occurred while setting parameters
### Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 违反唯一约束条件 (ZCRM.PK_CRM_USER)

; SQL []; ORA-00001: 违反唯一约束条件 (ZCRM.PK_CRM_USER)
 
分析:

DSC0000.png
 
 
 
http://my.oschina.net/realfighter/blog/366089
 
 
 
 
 
 
 
 
 
 
 
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-305529-1-1.html 上篇帖子: mybatis-spring 整合时的映射器映射原理 下篇帖子: MyBatis 入门(简明浅入易懂)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表