Spring事务实践

阅读更多

        大家都知晓的Spring的事物是基于动态机制的,支持CGLIB和JDK动态代理两种。如下所示:

一.CGLIB方式

        CGLIB代理无须必须实现接口。

package com.bijian.study.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bijian.study.dao.IUserMapper;
import com.bijian.study.model.User;

@Service("userServiceAOP")
public class UserServiceAOP {

	private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
	
	@Autowired
	private IUserMapper mapper;
	
	@Transactional
	public int txUpdateUsersWhenException() { // 事务性
		return innerMethod();
	}
	
	private int innerMethod() {
		User user = new User(1, "Before exception");
		int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
		log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId());
		User user2 = new User(1, "After exception");
		int i = 1 / 0; // 抛出运行时异常,事务回滚
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId());
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
		return 0;
	}
}

        调试发现确实是CglibAop代理,此时事务是生效的。

Spring事务实践_第1张图片

二.JDK动态代理

package com.bijian.study.service;

public interface UserService {

	public int txUpdateUsersWhenException();
}
package com.bijian.study.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bijian.study.dao.IUserMapper;
import com.bijian.study.model.User;

@Service("userService")
public class UserServiceImpl implements UserService {

	private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
	
	@Autowired
	private IUserMapper mapper;

	@Transactional
	public int txUpdateUsersWhenException() { // 事务性
		return innserMethod();
	}

	private int innserMethod() {
		User user = new User(1, "Before exception");
		int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
		log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId());
		User user2 = new User(1, "After exception");
		int i = 1 / 0; // 抛出运行时异常,事务回滚
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId());
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
		return 0;
	}
}

        调试发现确实是JDK动态代理,此时事务是生效的。

Spring事务实践_第2张图片

三.测试代码

package com.bijian.study.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bijian.study.service.UserService;
import com.bijian.study.service.UserServiceAOP;

public class SpringIntegrationTest {
	
    private static ApplicationContext ctx;
    
    static {
    	ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
  
    @Test  
    public void txUpdateUsersExceptionTest() {
    	
    	UserService userService = (UserService) ctx.getBean("userService");
        userService.txUpdateUsersWhenException();  
    }
    
    @Test  
    public void txUpdateUsersExceptionAOPTest() {
    	
    	UserServiceAOP userServiceAOP = (UserServiceAOP) ctx.getBean("userServiceAOP");
    	userServiceAOP.txUpdateUsersWhenException();  
    }
}

        applicationContext.xml




	
	
	
	
	
	
	
	
	
		
		
		
		
		
		
	

	
	
		
	

	
	
		
	

	
	
    
	
	
	
	
	
  		
  	

        database.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.235.1:3306/hbatis?characterEncoding=utf8
user_name=bijian
password=123456

 

四.将@Transactional放到非外部直接调用的方法上

        将@Transactional放到非外部直接调用的方法上,调试发现无代理,事务失效。

1.修改CGLIB方式的服务方法

package com.bijian.study.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bijian.study.dao.IUserMapper;
import com.bijian.study.model.User;

@Service("userServiceAOP")
public class UserServiceAOP {

	private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
	
	@Autowired
	private IUserMapper mapper;
	
	public int txUpdateUsersWhenException() { // 事务性
		return innerMethod();
	}
	
	@Transactional
	private int innerMethod() {
		User user = new User(1, "Before exception");
		int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
		log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId());
		User user2 = new User(1, "After exception");
		int i = 1 / 0; // 抛出运行时异常,事务回滚
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId());
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
		return 0;
	}
}

        @Transactional方法不是服务类的入口方法,无CGLIB代理,事务失效。

Spring事务实践_第3张图片

2.修改JDK动态代理方式的服务方法

package com.bijian.study.service;

public interface UserService {

	public int txUpdateUsersWhenException();
}
package com.bijian.study.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bijian.study.dao.IUserMapper;
import com.bijian.study.model.User;

@Service("userService")
public class UserServiceImpl implements UserService {

	private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
	
	@Autowired
	private IUserMapper mapper;

	public int txUpdateUsersWhenException() { // 事务性
		return innserMethod();
	}

	@Transactional
	private int innserMethod() {
		User user = new User(1, "Before exception");
		int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚
		log.info("{} new record was inserted successfully whose id: {}", affectedCount, user.getId());
		User user2 = new User(1, "After exception");
		int i = 1 / 0; // 抛出运行时异常,事务回滚
		int affectedCount2 = mapper.updateUser(user2); // 未执行
		log.info("{} new record was inserted successfully whose id: {}", affectedCount2, user.getId());
		if (affectedCount == 1 && affectedCount2 == 1) {
			return 1;
		}
		return 0;
	}
}

        @Transactional方法不是服务类的入口方法,无JDK动态代理,事务失效。

Spring事务实践_第4张图片
        测试前数据库中user表数据如下:

mysql> select * from user;
+----+--------+------+-------------------+
| id | name   | age  | address           |
+----+--------+------+-------------------+
|  1 | bijian |  120 | hangzhou,westlake |
+----+--------+------+-------------------+
1 row in set (0.00 sec)

        测试方法的innserMethod中虽然抛出异常,但事务并没有回滚,测试后数据库中user表数据如下:

mysql> select * from user;
+----+------+------+------------------+
| id | name | age  | address          |
+----+------+------+------------------+
|  1 | NULL |    0 | Before exception |
+----+------+------+------------------+
1 row in set (0.00 sec)
  • Spring事务实践_第5张图片
  • 大小: 64.8 KB
  • Spring事务实践_第6张图片
  • 大小: 58.7 KB
  • Spring事务实践_第7张图片
  • 大小: 59.5 KB
  • Spring事务实践_第8张图片
  • 大小: 61.5 KB
  • MyBatisStudy03.rar (9.8 MB)
  • 下载次数: 0
  • 查看图片附件

你可能感兴趣的:(Spring,Spring事务)