spring-boot-jpa事务入坑

这几日使用spring-boot忙着搭建自己小程序后台的过程中,持久层的框架使用的是jpa/hibernate。在搭建好数据库连接池后打算测试一下jpa的事务管理机制是否有效,于是写了一个测试的sevice;首先看看我的jpa配置,数据库以及连接池的就不展示了:

#jpa配置
jpa:
    show-sql: true
    properties:
      hibernate:
        hbm2ddl:
          auto: update

再贴一下要测试的实体:

#实体部分关键代码
@Entity
@Table(name = "wx_feedback")
public class Feedback {


    /**
     * id
     */
    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;



    /**
     * 联系人姓名
     */
    @Column(name = "contacts", length = 7)
    private String contacts;

该表的contacts字段长度设置为7,主要是为了之后测试报错后是否会回滚。同时根据JPA配置auto:update该配置,spring-boot项目启动时会自动更新建立该表。接下来编写测试存储代码:


未加事务

Dao层直接新建interface继承JpaRepository即可拥有常用的一些CRUD方法,service代码如下:

#为了测试插入多条数据,本方法暂不加上事务
public Object add(FeedbackParam param) {
   Feedback feedback = EntityUtil.copyObject(param, Feedback.class);
   feedback.setCreateDate(new Date());
   feedback.setContacts(param.getName());
   feedbackRepository.save(feedback);
   return ResultModel.success();
}

测试代码:

测试代码
@Test
public void contextLoads() {
    userFeedbackService.add(new FeedbackParam("数据1", "我要投诉你1"));
    userFeedbackService.add(new FeedbackParam("数据2", "我要投诉你2"));
    userFeedbackService.add(new FeedbackParam("数据3", "我要投诉你3"));
    userFeedbackService.add(new FeedbackParam("数据4", "我要投诉你4"));
    #字段超出限定长度,会报错
    userFeedbackService.add(new FeedbackParam("数据5", "我要投诉你546546465464"));
    userFeedbackService.add(new FeedbackParam("数据6", "我要投诉你6"));
    userFeedbackService.add(new FeedbackParam("数据7", "我要投诉你7"));
    userFeedbackService.add(new FeedbackParam("数据8", "我要投诉你8"));
    userFeedbackService.add(new FeedbackParam("数据9", "我要投诉你9"));
    userFeedbackService.add(new FeedbackParam("数据10", "我要投诉你10"));
    userFeedbackService.add(new FeedbackParam("数据11", "我要投诉你11"));
    userFeedbackService.add(new FeedbackParam("数据12", "我要投诉你12"));
    userFeedbackService.add(new FeedbackParam("数据13", "我要投诉你13"));  
}

运行该方法后,数据库数据为:

可以看出,未添加事务控制部分数据仍会提交,这就造成了数据的不完整性,接下来我们看看添加事务


JPA事务

根据JPA事务管理的用法,只要引入spring-data-jpa,spring-boot便会自动加上事务管理,JPA使用的是JpaTransactionManager。在具体的使用上只需加入@Transactional注解即可(要注意的一点,spring-boot中的测试单元方法默认事务会回滚,所以为了阻止回滚需要加上@Rollback(false)注解),网上有很多博客上说还需要在spring-boot启动类上加入@EnableTransactionManagement开启事务管理,其实并不用,spring-boot默认是开启事务管理的。于是我在刚才的测试方法上加上@Transactional后再次执行插入语句,发现数据库依然插入了四条语句,如上图。难道JPA的事务不起作用???思来想去,决定先看看相关的事务管理器,在启动类中加入方法(PlatformTransactionManager是其他事务管理的父接口):

@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager){
                                             System.out.println(">>>>>>>>>>>"+platformTransactionManager.getClass().getName());
        return new Object();
}

运行后打印的信息如下:

>>>>>>>>>>>org.springframework.orm.jpa.JpaTransactionManager

说明确实JPA的事务管理器加载没有问题,那么为何@Transactional注解没有生效,几经尝试,找到一个解决方法,指定@Transactional要使用的事务管理器事务便会回滚:

@Transactional(value = "jpaTransactionManager")

虽然说事务回滚的问题解决了 。但是这绝不是最好的解决方法,在各种搜索询问中,终于找到了真相:原来,jpa默认建表时用的引擎为MyISAM,而MyISAM却是不支持事务的,要想支持需要将表的存储引擎设为InnoDB。顺带说一下这两者的区别,Mysql有很多种引擎,常用的就是这两种;MyISAM相比于InnoDB比较简单,适用查询以及插入为主的应用,而InnoDB适合频繁修改以及涉及到安全性较高的应用。那么知道原因后如何解决?方法很简单只需要设置JPA建表默认的存储引擎即可,修改后的JPA的配置如下:

jpa:
    show-sql: true
    properties:
      hibernate:
        hbm2ddl:
          auto: update
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect

在最后一句指定hibernate方言,Mysql5.5之后的版本都默认采用InnoDB为存储引擎,所以指定了该版本的方言后,JPA建表便会采用InnoDB,至此入坑结束。

本文仅个人观点,仅供参考;如有错误,欢迎指正

你可能感兴趣的:(spring-boot)