@
目录
构建一个SpringBoot项目,增加以下代码:
实体类
/** * 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", "[email protected]"); userDAO.addUser(user1); // 增加一个与user1主键相同的用户 User user2 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user2); } //.... }
// 无事务 public void noneTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 增加一个与user1主键相同的用户 User user2 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user2); }
// 事务传播为PROPAGATION_REQUIRED @Transactional(propagation = Propagation.REQUIRED) public void requiredTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 增加一个与user1主键相同的用户 User user2 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user2); }
第二条数据插入时报重复主键错误
由于启用了事务,提示事务回滚,表中没有插入任何数据
// 事务传播为PROPAGATION_SUPPORTS // 调用的外层没有事务 @Transactional(propagation = Propagation.SUPPORTS) public void supportsTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 增加一个与user1主键相同的用户 User user2 = new User(100L, "Jack", "[email protected]"); 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", "[email protected]"); userDAO.addUser(user1); // 增加一个与user1主键相同的用户 User user2 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user2); }
// 事务传播为PROPAGATION_MANDATORY @Transactional(propagation = Propagation.MANDATORY) public void mandatoryTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); }
由于调用外层没有启用事务,该段测试代码判断当前事务不存在,则会抛出不存在事务的错误
接下来使用调用方的外层启用事务,再调用这段测试代码:
// 事务传播为PROPAGATION_MANDATORY // 调用方启用事务 @Transactional public void callMandatoryTransaction() throws SQLException { User user = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user); mandatoryTransaction(); } @Transactional(propagation = Propagation.MANDATORY) public void mandatoryTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); }
测试程序在插入第二条数据时报主键错误
由于调用方启用事务,事务回滚,没有插入任何数据。
表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
针对这种特性,我们做一个有趣的实验:调用方启用默认事务,并调用事务传播为PROPAGATION_REQUIRES_NEW的程序,并故意造成事务回滚。
// 调用方启用默认事务,并调用事务传播为PROPAGATION_REQUIRES_NEW的程序,在外层故意造成事务回滚 @Transactional public void callRequiresNewTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); requiresNewTransaction(); // 增加一个主键重复的用户,故意造成事务回滚 User user2 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user2); } // 事务传播为PROPAGATION_REQUIRES_NEW @Transactional(propagation=Propagation.REQUIRES_NEW) public void requiresNewTransaction() throws SQLException { User user = new User(101L, "Jack", "[email protected]"); userDAO.addUser(user); }
测试情况如下:在外层事务造成回滚后,表中没有插入任何数据。
接下来再改下程序,调用方启用默认事务,并调用事务传播为PROPAGATION_REQUIRES_NEW的程序,但在调用的程序内层故意造成事务回滚。
// 调用方启用默认事务,并调用事务传播为PROPAGATION_REQUIRES_NEW的程序 @Transactional public void callRequiresNewTransaction() throws SQLException { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 调用事务传播为PROPAGATION_REQUIRES_NEW的过程 requiresNewTransaction(); User user2 = new User(101L, "Rose", "[email protected]"); userDAO.addUser(user2); } // 事务传播为PROPAGATION_REQUIRES_NEW // 内层错误造成事务回滚 @Transactional(propagation = Propagation.REQUIRES_NEW) public void requiresNewTransaction(){ // 增加一个主键重复的用户,故意造成事务回滚 User user2 = new User(100L, "Jack", "[email protected]"); 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", "[email protected]"); userDAO.addUser(user2); } }
// 主测试类启用默认事务,并调用Propagation.NOT_SUPPORTED的方法 @Transactional public void callNotSupportedTransaction() { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 调用事务传播为Propagation.NOT_SUPPORTED的过程 userServiceTest.notSupportedTransaction(); // 增加重复用户数据 User user2 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user2); }
// 调用方启用默认事务,并调用Propagation.NEVER的过程 // 调用方启用默认事务,并调用Propagation.NEVER的过程 @Transactional public void callNeverTransaction { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 调用事务传播为Propagation.NEVER的过程 userServiceTest.neverTransaction(); } // 事务传播为Propagation.NEVER的过程 @Transactional(propagation = Propagation.NEVER) public void neverTransaction() { User user2 = new User(101L, "Rose", "[email protected]"); userDAO.addUser(user2); }
// 调用方不起事务,并调用Propagation.NESTED的过程 public void callNestedTransaction(User user) { User user1 = new User(100L, "Jack", "[email protected]"); userDAO.addUser(user1); // 调用事务传播为Propagation.NEVER的过程 userServiceTest.nestedTransaction(); } // 事务传播为Propagation.NESTED @Transactional(propagation = Propagation.NESTED) public void nestedTransaction() { User user2 = new User(101L, "Rose", "[email protected]"); userDAO.addUser(user2); // 插入重复数据,造成主键冲突 User user3 = new User(101L, "Rose", "[email protected]"); userDAO.addUser(user3); }
原文链接:https://www.cnblogs.com/zhuhuix/p/13496966.html