更多精彩博文,欢迎访问个人我的博客javascript
SpringBoot版本:2.1.4.RELEASEjava
java版本:1.8mysql
文中所说JPA皆指spring-boot-starter-data-jpaspring
在JPA中保存一个对象,仅须要该对象,一个仓储便可。
StudentDO实体类:sql
@Getter @Setter @Entity @Table(name = "t_student") public class StudentDO { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column private Long id; @Column private String seq; @Column private String name; @Column private int sex; }
JPA仓储:数据库
@Repository public interface StudentRepo extends JpaRepository<StudentDO, String> { }
通常的,咱们只须要调用StudentRepo.save()方法便可完成对实体对象的保存操做。markdown
@Test public void testSave() { StudentDO student = new StudentDO(); student.setName("张三"); student.setSex(1); student.setSeq("123456"); studentRepo.save(student); Assert.assertNotNull(student.getId()); }
若是咱们但愿student的seq值由系统自动生成,且生成规则为“yyMMdd + 8位自增序列”(例如19060310000000)又该如何实现呢?oracle
首先想到的是该如何生成这一串序列,mysql不像oracle自身支持sequence,所以在这里能够借用函数以及额外的sequence表来实现这一操做,网上有不少实现方式,这里就再也不赘述。app
如今已经有了函数getseq('student_seq')能够获取到该序列,该如何将其应用到保存对象的方法中?显然的一个问题是,像上面那样再直接调用save方法已经行不通了,应该得须要自定义插入的sql实现。async
一个容易想到的办法是,在StudentDO类上使用注解@SQLInsert来定义insert的实现,它写起来应该会像这个样子:
@SQLInsert(sql = "INSERT INTO t_student(seq, name, sex) VALUES (getseq('student_seq'), ?, ?")
这条sql语句自己并无什么问题,再次调用save()方法也确实可以执行。可是很惋惜,它确会抛出一个sql异常:
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
显然是程序认为有多少个参数,就得有多少个“?”与之匹配,目前我并无找到解决这个问题的方案,因此这种方法宣告失败。
既然@SQLInsert行不通,或许能够考虑使用@Query注解来自定义一个实现。咱们能够在StudentRepo中定义这样一个方法:
@Transactional @Modifying @Query(value = "INSERT INTO t_student(seq, name, sex) VALUES (getseq('student_seq'), :#{#student.name}, :#{#student.sex})", nativeQuery = true) int insert(@Param("student") StudentDO student);
试着运行一下,结果很成功,对象被正常的存储到数据库中,而且seq的取值也正常。看上去咱们的问题已经获得了解决,但事实真的如此么?
上面的例子中,咱们成功经过JPA调用了mysql函数将对象存储到数据库中。但上面的例子只提供了单个保存的方法,若是咱们想批量保存呢?@Query里面的sql可以进行改造么?我并无找到@Query中使用List