1. Spring Boot常用配置項
基於Spring Boot 2.0.6.RELEASE
1.1 配置屬性類
spring.jpa
前綴的相關配置項定義在JpaProperties
類中,
1.2 自動裝配類
涉及到的自動配置類包括:JpaBaseConfiguration
,HibernateJpaAutoConfiguration
1.3 常用配置項
# 是否開啟JPA Repositories,缺省: true
spring.data.jpa.repositories.enabled=true
# JPA數據庫類型,默認可以自動檢測,也能通過設置spring.jpa.database-platform達到同樣效果
spring.jpa.database=ORACLE
# 數據庫平台,常見的值如:
# org.hibernate.dialect.Oracle10gDialect
# org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
# 是否使用JPA初始化數據庫,可以在啟動時生成DDL創建數據庫表,缺省為false
spring.jpa.generate-ddl = false
# 更細粒度的控制JPA初始化數據庫特性,用來設定啟動時DDL操作的類型,下文有詳細介紹
# 內嵌數據庫 hsqldb, h2, derby的缺省值為create-drop
# 非內嵌數據庫的缺省值為none
spring.jpa.hibernate.ddl-auto = update
# Hibernate操作時顯示真實的SQL, 缺省:false
spring.jpa.show-sql = true
# Hibernate 5 隱含命名策略類的全限定名
spring.jpa.hibernate.naming.implicit-strategy=
# Hibernate 5 物理命名策略類的全限定名
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
spring.jpa.hibernate.use-new-id-generator-mappings=
# 額外設置JPA配置屬性,通常配置項是特定實現支持的,如Hibernate常有下面的幾條配置項
spring.jpa.properties.* =
# 將SQL中的標識符(表名,列名等)全部使用引號括起來
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
# 日志記錄執行的SQL
spring.jpa.properties.hibernate.show_sql = true
# 是否將格式化SQL日志
spring.jpa.properties.hibernate.format_sql = true
# 是否注冊OpenEntityManagerInViewInterceptor. 綁定JPA EntityManager 到請求線程中. 默認為: true.
spring.jpa.open-in-view=true
# Hibernate 4 命名策略的全類名,Hibernate 5不再適用
spring.jpa.hibernate.naming-strategy=
1.4 配置項 spring.jpa.database
配置項spring.jpa.database
的值通常可以自動檢測,可取值包括了:
public enum Database {
DEFAULT,
DB2,
DERBY,
H2,
HSQL,
INFORMIX,
MYSQL,
ORACLE,
POSTGRESQL,
SQL_SERVER,
SYBASE
}
1.5 配置項spring.jpa.generate-ddl 和 spring.jpa.hibernate.ddl-auto
配置項spring.jpa.generate-ddl
管理是否開啟自動初始化Schema特性,
配置項spring.jpa.hibernate.ddl-auto
進一步控制啟動時初始化Schema的特性,有以下可選值:
create
, 啟動時刪除上一次生成的表,並根據實體類生成表,表中的數據將被清空;create-drop
,啟動時根據實體類生成表,sessionFactory
關閉時刪除表;update
,啟動時根據實體類生成表,當實體的屬性變動時,表結構也會更新,開發階段可以使用該屬性;validate
,啟動時驗證實體類和數據表是否一致,在數據結構穩定時可以采取該選項;none
,不采取任何操作;
1.6 配置項hibernate.globally_quoted_identifiers
配置項hibernate.globally_quoted_identifiers
用來在SQL中加入引號,以解決某些場景中SQL標識符(表名,列名等)出現了數據庫關鍵字的情形。
Oracle中,該屬性給標識符加雙引號,注意Oracle雙引號中的內容區分大小寫;
MySQL中,該屬性給標識符加反引號(沒錯,就是鍵盤數字1左面的那個`),注意默認情況下,MySQL的表名區分大小寫,但列名不區分大小寫,在反引號中也是如此。
2. 開發常用注解——表/實體類使用
2.1 @Entity
@Entity
用在實體類上,表示這是一個和數據庫表映射的實體類。
2.2 @Table
@Table
用來聲明實體類對應的表信息。包括表名稱、索引等。
2.3 @SQLDelete,
@SQLDelete
用來自定義刪除語句,
如果不想使用JPA Repository自帶的刪除語句,就可以使用該注解重寫,如常見的軟刪除:
@Entity
@Table(name = "App")
@SQLDelete(sql = "Update App set isDeleted = 1 where id = ?")
@Where
@Where
用來指定默認查詢條件,可以用來配合軟刪除。
@Entity
@Table(name = "App")
@SQLDelete(sql = "Update App set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
2.4 @MappedSuperclass
@MappedSuperclass
用來定義若干表中公共的字段,將它們封裝在一個基類中,基類上使用該注解,則其子實體類將自動獲得父類中的字段映射關系,同時不需要額外為父類建立真實的表,也就是真正的表只對應@MappedSuperclass
的子類。
2.5 @Inheritance
@MappedSuperclass
指定了實體類之間是可以存在層次關系的,通過@Inheritance
可以進一步管理層次關系,其取值InheritanceType
有以下枚舉變量:
public enum InheritanceType {
/** A single table per class hierarchy. */
SINGLE_TABLE,
/** A table per concrete entity class. */
TABLE_PER_CLASS,
/**
* A strategy in which fields that are specific to a
* subclass are mapped to a separate table than the fields
* that are common to the parent class, and a join is
* performed to instantiate the subclass.
*/
JOINED
}
例如
父類聲明如下,意味着每個子實體類對應了一張表
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity
子實體類復用父類聲明的域/字段:
@Entity
@Table(name="App")
public class AppEntity entends BaseEntity
3. 開發常用注解——字段/域使用
3.1 @Column
@Column
聲明一個表字段與域/方法的映射,其屬性可以進一步指定是否可為NULL
,是否唯一等細節。
3.2 @Id
@Id
標注一個屬性,表示該屬性映射為數據庫的主鍵。
單獨使用@Id
來標識實體類的單個域映射為數據庫表的主鍵,對於聯合主鍵而言,就要配合@IdClass
使用。
- 定義一個(外部)主鍵類,主鍵類中聲明了實體類(目標表)聯合主鍵中的所有主屬性,主鍵類需實現
Serializable
接口; - 在真正的實體類上使用
@IdClass
,以上一步定義的主鍵類作為參數; - 實體類的主屬性必須和主鍵類中的主屬性完全對應(個數,類型,名稱);
- 在實體類的所有主屬性上面添加
@Id
注解;
示例
外部主鍵類:
public class RoleUserId implements Serializable {
private Long roleId;
private Long userId;
}
實體類:
@Entity
@Table(name = "TB_ROLE_USER")
@IdClass(RoleUserId.class)
public class RoleUserDO {
@Id
private Long roleId;
@Id
private Long userId;
// ...
}
3.3 @GeneratedValue
@GeneratedValue
設置字段的自動生成方式。
其strategy
屬性取值為枚舉GenerationType
:
/**
* Indicates that the persistence provider must assign
* primary keys for the entity using an underlying
* database table to ensure uniqueness.
*/
TABLE,
/**
* Indicates that the persistence provider must assign
* primary keys for the entity using a database sequence.
*/
SEQUENCE,
/**
* Indicates that the persistence provider must assign
* primary keys for the entity using a database identity column.
*/
IDENTITY,
/**
* Indicates that the persistence provider should pick an
* appropriate strategy for the particular database. The
* <code>AUTO</code> generation strategy may expect a database
* resource to exist, or it may attempt to create one. A vendor
* may provide documentation on how to create such resources
* in the event that it does not support schema generation
* or cannot create the schema resource at runtime.
*/
AUTO
使用自增的數據庫列生成主鍵是一種常見的主鍵生成方式,MySQL支持Identity列。
Oracle 12c以后支持Identity Column(身份列),可以使用GenerationType.IDENTITY
作為生成策略,此時無需再使用@SequenceGenerator
指定對應序列。此前的Oracle通常使用序列實現自增字段,需要將生成策略指定為GenerationType.SEQUENCE
並配合@SequenceGenerator
(下文)使用。
Oracle 12c新增Identity Column的使用請閱讀:https://www.cnblogs.com/zyon/p/11067115.html
使用身份列生成自增主鍵時,在主鍵屬性上使用@Id
和@GeneratedValue(strategy = GenerationType.IDENTITY)
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
// …
}
@GeneratedValue#generator
屬性指定主鍵生成器的名稱,需要與@SequenceGenerator
或@TableGenerator
的名稱對應起來。
3.4 @SequenceGenerator
如果使用序列方式生成主鍵,@SequenceGenerator
指定自動生成主鍵時對應的序列(Sequence)。
@SequenceGenerator#name
指定序列生成器的名稱,@GeneratedValue#generator
通過引用該值與具體的序列生成器關聯,進而關聯具體的序列。@SequenceGenerator#sequenceName
指定自動生成主鍵時的物理序列名稱;@SequenceGenerator#initialValue
屬性指定序列初值;@SequenceGenerator#allocationSize
指定自增步長;
實例:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
@SequenceGenerator(name = "sequence", sequenceName = "ID_SEQ", allocationSize = 1)
@Column(name = "Id")
private long id;
3.5 JPA大對象支持
常用相關注解
- @Lob
- @Basic
3.5.1 在字符串型域上用@Lob
@Lob
private String description;
- oracle映射字段的類型是
CLOB
,java.sql.Clob
,Character[]
,char[]
和java.lang.String
將被持久化為Clob
類型。 - mysql中映射字段的類型是
longtext
。
3.5.2 在二進制等類型域上用@Lob
- oracle中
java.sql.Blob
,Byte[]
,byte[]
和Serializable
實現類將被持久化為Blob
類型。 - mysql中對應
longblob
。
@Lob
持久化為Blob
或者Clob
類型,根據get
方法的返回值不同,自動進行Clob
和Blob
的轉換。
3.5.3 大對象字段的延遲加載
@Lob
@Basic(fetch=FetchType.LAZY)
private Byte[] file;
因為大對象數據一般占用的內存空間比較大,所以通常使用延遲加載的方式:@Basic
注解設置加載方式為FetchType.LAZY
。
問題:
延遲加載是延遲到什么時候?這個問題一直沒有找到確切的解答。
4. 常用Repository開發
4.1 Repository
接口
public interface Repository<T, ID>
最基礎的Repository接口,不提供任何操作方法。
4.2 CrudRepository
接口
public interface CrudRepository<T, ID> extends Repository<T, ID>
提供CRUD基本操作的Repository接口。
4.3 PagingAndSortingRepository
接口
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID>
它繼承 CrudRepository
接口,在 CrudRepository
基礎上新增了兩個與分頁有關的方法。
也可以不將自定義的持久層接口直接繼承PagingAndSortingRepository
,而是繼承 Repository
或 CrudRepository
的基礎上,在自定義方法參數列表最后增加一個 Pageable
或 Sort
類型的參數,用於指定分頁或排序信息,可以實現比直接繼承 PagingAndSortingRepository
更大的靈活性。
4.4 JpaRepository
接口
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
JpaRepository
繼承PagingAndSortingRepository
,是針對 JPA 技術提供的接口,它在父接口的基礎上,提供了其他一些方法,比如flush()
,saveAndFlush()
,deleteInBatch()
等。
4.5 自定義JPA Repository方法
自定義JPA Repository方法,應參考以下規范:
注意兩點:
- 出現在方法名中用於組合查詢條件等的是實體類的域名稱,而不是數據庫的表字段;
- 這種方式用來組合一些固定模式的SQL,生成SQL的過程對程序員是透明的,程序員不用自己寫SQL。
4.6 @Query
注解
org.springframework.data.jpa.repository.Query
注解用來指定JPA Repository方法對應的查詢HSQL。
示例:
import org.springframework.data.repository.query.Param;
//...
@Query("select a from App a where a.name LIKE %:name%")
List<App> findByName(@Param("name") String name);
需要注意的是,@Query
中的參數HQL默認不是真實的SQL語句,而是面向對象的。
通常我們可以使用@Table
指定實體類對應的表名,如果實體類的類名和對應的表名不同,@Query
中應該使用類名,同時參數HQL中使用的是實體類的域名稱而不是實際的字段名。
如不這樣,例如在@Query
的參數HQL中使用了實際的表名而非實體類名,則會報:QuerySyntaxException: XXX is not mapped.
。
如果希望使用原生SQL,將@Query#nativeQuery
設置為true
即可:
@Query(nativeQuery = true, value = "SELECT * FROM AUTH_USER WHERE name = :name1 OR name = :name2 ")
List<UserDO> findSQL(@Param("name1") String name1, @Param("name2") String name2);
4.7 @Modifying
注解
org.springframework.data.jpa.repository.Modifying
注解標識一個JPA Repository方法對應的SQL會修改數據庫。
示例:
@Modifying
@Query("update appnamespace set isDeleted=1, dataChangeLastModifiedBy = ?3 where appId = ?1 and name = ?2")
int delete(String appId, String namespaceName, String operator);
參考: