更多精彩博文,歡迎訪問我的個人博客
說明
SpringBoot版本:2.1.4.RELEASE
java版本:1.8
文中所說JPA皆指spring-boot-starter-data-jpa
使用JPA保存一個Student對象
在JPA中保存一個對象,僅需要該對象,一個倉儲即可。
StudentDO實體類:
@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, Long> {
}
一般的,我們只需要調用StudentRepo.save()方法即可完成對實體對象的保存操作。
@Test
public void testSave() {
StudentDO student = new StudentDO();
student.setName("張三");
student.setSex(1);
student.setSeq("123456");
studentRepo.save(student);
Assert.assertNotNull(student.getId());
}
在插入過程中使用mysql函數
如果我們希望student的seq值由系統自動生成,且生成規則為“yyMMdd + 8位自增序列”(例如19060310000000)又該如何實現呢?
首先想到的是該如何生成這一串序列,mysql不像oracle自身支持sequence,因此在這里可以借用函數以及額外的sequence表來實現這一操作,網上有很多實現方式,這里就不再贅述。
現在已經有了函數getseq('student_seq')可以獲取到該序列,該如何將其應用到保存對象的方法中?顯然的一個問題是,像上面那樣再直接調用save方法已經行不通了,應該得需要自定義插入的sql實現。
一個容易想到的辦法是,在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