当前位置 : 主页 > 编程语言 > java >

在ssm框架中进行事务管理遇到的一些坑

来源:互联网 收集:自由互联 发布时间:2023-12-28
最近公司项目是用的java的ssm框架,然后需要用到事务管理,数据库是sqlserver,然后遇到一些问题,写个博客记录下。 首先项目需求是在控制器中对若干个数据库进行数据的操作,然后

最近公司项目是用的java的ssm框架,然后需要用到事务管理,数据库是sqlserver,然后遇到一些问题,写个博客记录下。

首先项目需求是在控制器中对若干个数据库进行数据的操作,然后当其中某一个操作发生异常,则进行事务回滚,并且其中某些操作需要读取前面对数据库增加的数据,所以数据库事务级别需要设置为READ_UNCOMMITTED

因为是第一次接触事务管理,所以按照官方文档示例,在server层采用注解的方式,首先在applicationContext.xml配置文件中添加事务管理支持

<tx:annotation-driven transaction-manager="transactionManager"/>
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource" />
  </bean>
1
2
3
4
<tx:annotation-driven transaction-manager="transactionManager"/>
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource" />
  </bean>

然后在server实现类上添加注解

	@Override
	@Transactional(
			propagation=Propagation.REQUIRES_NEW,
			isolation=Isolation.READ_UNCOMMITTED,
			rollbackForClassName="Exception"
	)
	public String add(PO_Podetails[] data) {
    // ...
  }
1
2
3
4
5
6
7
@Override
	@Transactional(
			propagation=Propagation.REQUIRES_NEW,
			isolation=Isolation.READ_UNCOMMITTED,
			rollbackForClassName="Exception"
	)
	public String add(PO_Podetails[] data) {

其中在注解中设置了事务的传播属性,事务隔离级别和回滚
但是运行发现后事务回滚虽然生效了,但是仍然查询不到本次提交的数据,初步判断事务隔离级别没有生效,在网上也并没有找到相应的解决办法,然后想尝试在controller中添加事务,采用编程式事务管理

@Resource
private PlatformTransactionManager transactionManager;
@ResponseBody
@RequestMapping("/submitPO_Podetails")
public String submitPO_Podetails(@RequestBody PO_Podetails[] data) {
	 DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
    defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
    try{
    	//这里是对数据库的一系列操作

    	 //没有异常便手动提交事务
        transactionManager.commit(status);
        printJson(response,result(200,"ok"));

    }catch (Exception e) {
    	//有异常便回滚事务
        transactionManager.rollback(status);
        e.printStackTrace();
        printJson(response,result(500,"false"));
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Resource
private PlatformTransactionManager transactionManager;
@ResponseBody
@RequestMapping("/submitPO_Podetails")
public String submitPO_Podetails(@RequestBody PO_Podetails[] data) {
	 DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
    defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
    try{
    	//这里是对数据库的一系列操作

    	 //没有异常便手动提交事务
        transactionManager.commit(status);
        printJson(response,result(200,"ok"));

    }catch (Exception e) {
    	//有异常便回滚事务
        transactionManager.rollback(status);
        e.printStackTrace();
        printJson(response,result(500,"false"));
    }

然而结果还是跟前面的一样,还是读取不带脏数据,然后在控制台一条一条查看sql执行语句,发现一个奇怪的问题,同一条语句如果执行第二次则不会再执行,会调用第一次查到的数据,上网看到了相同问题,有解决方法,
使用spring @Transaction事务时,在for循环中需要多次执行同一查询语句,第一次查询出对象后,对对象进行修改后,结果再进行第二次查询的时候,查询返回的数据是自己第一次修改后的数据。因为业务需要每次查询都需要取更改数据库,以后的查询都会根据上一次循环修改后的值进行操作。

解决方法:

在xml文件 select语句添加 flushCache=”true” ,告诉mybatis查询结束后刷新缓存,不记录查询结果到一级缓存中

原因:

mybatis对查询的语句会存在一级缓存中,如果在一个事务中,mybatis对同一个session多次查询同一个sql语句就会去找缓存而不是再去查一次数据库

网友评论