事务传播
定义 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常。 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。 |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
/**
* User.java : 用户类
*/
@Entity
public class User implements Serializable {
// 用户id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 用户名
@NotBlank(message = "用户名称不能为空")
@Column(name="name")
private String name;
// 邮箱
@Column(name="email")
@Pattern(message ="邮箱格式不符", regexp = "^[A-Za-z0-9\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
private String email;
public User(){}
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}
/**
* 用户数据访问层(DAO)接口
*/
public interface UserDAO {
// 查找所有用户
List<User> findAll();
// 根据id查找用户
User findById(Long id) throws SQLException;
// 新增用户
Long addUser(User user) throws SQLException;
// 更新用户
void updateUser(User user);
// 删除用户
void deleteById(Long id);
// 自定义添加通过用户名称查找用户信息
List<User> findByName(String name);
}
/**
* 使用JdbcTemplate模板类实现用户数据访问层
*
*/
@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List<User> findAll() {
return jdbcTemplate.query("select id,name,email from user;",
new Object[]{}, new BeanPropertyRowMapper<>(User.class));
}
@Override
public User findById(Long id) {
return jdbcTemplate.queryForObject("select id,name,email from user where id=?;",
new Object[]{id}, new BeanPropertyRowMapper<>(User.class));
}
@Override
public Long addUser(User user) {
return Integer.toUnsignedLong(
jdbcTemplate.update("insert into user(id,name,email) values(?,?,?);"
, user.getId(), user.getName(), user.getEmail()));
}
@Override
public void updateUser(User user) {
jdbcTemplate.update("update user set name=?,email=? where id =?;"
, user.getName(), user.getEmail(), user.getId());
}
@Override
public void deleteById(Long id) {
jdbcTemplate.update("delete from user where id=?", new Object[]{id});
}
@Override
public List<User> findByName(String name) {
return jdbcTemplate.query("select id,name,email from user where name=?;",
new Object[]{name}, new BeanPropertyRowMapper<>(User.class));
}
}
/**
* 事务传播测试案例
*/
public class TransactionalTest {
@Autowired
private UserDAO userDAO;
// 无事务
public void noneTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 增加一个与user1主键相同的用户
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
//....
}
// 无事务
public void noneTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 增加一个与user1主键相同的用户
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
// 事务传播为PROPAGATION_REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void requiredTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 增加一个与user1主键相同的用户
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
// 事务传播为PROPAGATION_SUPPORTS
// 调用的外层没有事务
@Transactional(propagation = Propagation.SUPPORTS)
public void supportsTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 增加一个与user1主键相同的用户
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
// 事务传播为PROPAGATION_SUPPORTS
// 调用方已启用事务
@Transactional
public void callSupportsTransaction() throws SQLException {
supportsTransaction();
}
@Transactional(propagation = Propagation.SUPPORTS)
public void supportsTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 增加一个与user1主键相同的用户
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
// 事务传播为PROPAGATION_MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
}
// 事务传播为PROPAGATION_MANDATORY
// 调用方启用事务
@Transactional
public void callMandatoryTransaction() throws SQLException {
User user = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user);
mandatoryTransaction();
}
@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
}
// 调用方启用默认事务,并调用事务传播为PROPAGATION_REQUIRES_NEW的程序,在外层故意造成事务回滚
@Transactional
public void callRequiresNewTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
requiresNewTransaction();
// 增加一个主键重复的用户,故意造成事务回滚
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
// 事务传播为PROPAGATION_REQUIRES_NEW
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void requiresNewTransaction() throws SQLException {
User user = new User(101L, "Jack", "Jack@163.com");
userDAO.addUser(user);
}
// 调用方启用默认事务,并调用事务传播为PROPAGATION_REQUIRES_NEW的程序
@Transactional
public void callRequiresNewTransaction() throws SQLException {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 调用事务传播为PROPAGATION_REQUIRES_NEW的过程
requiresNewTransaction();
User user2 = new User(101L, "Rose", "Rose@163.com");
userDAO.addUser(user2);
}
// 事务传播为PROPAGATION_REQUIRES_NEW
// 内层错误造成事务回滚
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNewTransaction(){
// 增加一个主键重复的用户,故意造成事务回滚
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
/**
* 测试 Propagation.NOT_SUPPORTED
*/
@Service
public class UserServiceTest {
@Autowired
private UserDAOImpl userDAO;
// 事务传播为Propagation.NOT_SUPPORTED
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void notSupportedTransaction(){
User user2 = new User(101L, "Rose", "Rose@163.com");
userDAO.addUser(user2);
}
}
// 主测试类启用默认事务,并调用Propagation.NOT_SUPPORTED的方法
@Transactional
public void callNotSupportedTransaction() {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 调用事务传播为Propagation.NOT_SUPPORTED的过程
userServiceTest.notSupportedTransaction();
// 增加重复用户数据
User user2 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user2);
}
// 调用方启用默认事务,并调用Propagation.NEVER的过程
// 调用方启用默认事务,并调用Propagation.NEVER的过程
@Transactional
public void callNeverTransaction {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 调用事务传播为Propagation.NEVER的过程
userServiceTest.neverTransaction();
}
// 事务传播为Propagation.NEVER的过程
@Transactional(propagation = Propagation.NEVER)
public void neverTransaction() {
User user2 = new User(101L, "Rose", "Rose@163.com");
userDAO.addUser(user2);
}
// 调用方不起事务,并调用Propagation.NESTED的过程
public void callNestedTransaction(User user) {
User user1 = new User(100L, "Jack", "Jack@163.com");
userDAO.addUser(user1);
// 调用事务传播为Propagation.NEVER的过程
userServiceTest.nestedTransaction();
}
// 事务传播为Propagation.NESTED
@Transactional(propagation = Propagation.NESTED)
public void nestedTransaction() {
User user2 = new User(101L, "Rose", "Rose@163.com");
userDAO.addUser(user2);
// 插入重复数据,造成主键冲突
User user3 = new User(101L, "Rose", "Rose@163.com");
userDAO.addUser(user3);
}