集成spring-data-jpa
JPA Spring Data
1、致力于减少数据访问层的开发量。
2、开发者唯一要做的,就是声明持久层接口 其他都交给Spring data JPA完成
3、框架怎么可能代替开发者实现业
pom.xml依赖包
<!-- spring-data-jpa 该版本对应的spring是5.2.3.RELEASE,必须一致 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<!-- hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.17.Final</version>
</dependency>
配置数据源spring-data-source.xml
数据源配置可以放在spring-jpa.xml中,这里单独放到一个文件中,可以与mybatis公用一个数据源
<bean id="hikariDataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="minimumIdle" value="${hikari.minimumIdle}"/>
<property name="autoCommit" value="${hikari.autoCommit}"/>
<property name="idleTimeout" value="${hikari.idleTimeout}"/>
<property name="maximumPoolSize" value="${hikari.maximumPoolSize}"/>
<property name="poolName" value="${hikari.poolName}"/>
<property name="maxLifetime" value="${hikari.maxFifetime}"/>
<property name="connectionTimeout" value="${hikari.connectionTimeout}"/>
<property name="connectionTestQuery" value="${hikari.connectionTestQuery}"/>
</bean>
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=mysql
jdbc.driver=com.mysql.cj.jdbc.Driver
# hikari数据库连接池相关信息配置
hikari.minimumIdle=5
hikari.maximumPoolSize=20
hikari.autoCommit=true
hikari.idleTimeout=30000
hikari.poolName=DatebookHikariCP
hikari.maxFifetime=1800000
hikari.connectionTimeout=30000
hikari.connectionTestQuery=SELECT 1
配置spring-data-jpa.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--配置JPA的entityManagerFactory-->
<bean name="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="hikariDataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<!--配置jpa扫描包实体类包-->
<property name="packagesToScan" value="org.example.demo.jpa.entity"/>
<!--JPA属性-->
<property name="jpaProperties">
<props>
<!-- 二级缓存相关 -->
<!--
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="net.sf.ehcache.configurationResourceName">ehcache-hibernate.xml</prop>
-->
<!-- 5.0之前 生成的数据表的列的映射策略 与java一致-->
<!--<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>-->
<!-- 5.0 生成的数据表的列的映射策略 下划线-->
<!--SpringImplicitNamingStrategy 自定义类 springboot中jpa生成策略-->
<prop key="hibernate.implicit_naming_strategy">
org.hibernate.boot.model.naming.SpringImplicitNamingStrategy
</prop>
<!--SpringPhysicalNamingStrategy 自定义类 springboot中jpa生成策略-->
<prop key="hibernate.physical_naming_strategy">
org.hibernate.boot.model.naming.SpringPhysicalNamingStrategy
</prop>
<!--<prop key="hibernate.implicit_naming_strategy">org.hibernate.boot.model.naming.ImplicitNamingStrategy</prop>-->
<!-- hibernate 基本属性 -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!--配置事务管理器-->
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--配置支持事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--配置Spring data-->
<!--加入jpa命名空间-->
<!--base-package 用于扫描 repository bean所在的路径-->
<jpa:repositories base-package="org.example.demo.jpa.repository"
entity-manager-factory-ref="entityManagerFactory">
</jpa:repositories>
</beans>
自定义jpa生成数据库字段策略
hibernate5的版本使用下面两个策略,将Java驼峰命名转成数据库下划线
hibernate.implicit_naming_strategy
>xxx.SpringImplicitNamingStrategy
hibernate.physical_naming_strategy
>xxx.SpringPhysicalNamingStrategy
这两个类的源码是springboot中使用jpa生成策略,直接拿过来用即可
public class SpringImplicitNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl {
public SpringImplicitNamingStrategy() {
}
public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {
String name = source.getOwningPhysicalTableName() + "_" + source.getAssociationOwningAttributePath().getProperty();
return this.toIdentifier(name, source.getBuildingContext());
}
}
------------------------------
public class SpringPhysicalNamingStrategy implements PhysicalNamingStrategy {
public SpringPhysicalNamingStrategy() {
}
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return this.apply(name, jdbcEnvironment);
}
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return this.apply(name, jdbcEnvironment);
}
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return this.apply(name, jdbcEnvironment);
}
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return this.apply(name, jdbcEnvironment);
}
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return this.apply(name, jdbcEnvironment);
}
private Identifier apply(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name == null) {
return null;
} else {
StringBuilder builder = new StringBuilder(name.getText().replace('.', '_'));
for (int i = 1; i < builder.length() - 1; ++i) {
if (this.isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
builder.insert(i++, '_');
}
}
return this.getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
}
}
protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
if (this.isCaseInsensitive(jdbcEnvironment)) {
name = name.toLowerCase(Locale.ROOT);
}
return new Identifier(name, quoted);
}
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return true;
}
private boolean isUnderscoreRequired(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
}
}
创建实体类对象和repository层
// person.java
@Table(name = "jpa_person")
@Entity
@Data
@Accessors(chain = true)
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String lastName;
private String email;
@Temporal(TemporalType.DATE)
private Date brith;
}
//PersonRepository接口
public interface PersonRepository extends JpaRepository<Person,Integer> {
}
二级缓存配置
pom.xml
<!-- 与org.hibernate版本一致 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.2.17.Final</version>
</dependency>
spring-jpa.xml中配置
<!--JPA属性-->
<property name="jpaProperties">
<props>
......
<!--二级缓存配置-->
<!--开启二级缓存-->
<prop key="hibernate.use_second_level_cache">true</prop>
<!--单例模式-->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<!--使用缓存查询-->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!--查看是否使用了缓存-->
<!--<prop key="hibernate.generate_statistics">true</prop>-->
<prop key="net.sf.ehcache.configurationResourceName">ehcache.xml</prop>
</props>
</property>
ehcache.xml
将该文件放在resource路径下
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="sampleCache1"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
</ehcache>
实体类上加@Cache注解
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Product {
......
}
测试结果
@Test
public void testJpaFirstCache() {
Product product = productRepository.getOne(1);
log.error("product=" + product.getProductName());
Product product1 = productRepository.getOne(1);
log.error("product1=" + product1.getProductName());
}
***************
打印结果,只有一条SQL,两条结果
Hibernate:
select
product0_.id as id1_6_0_,
product0_.product_name as product_2_6_0_
from
jpa_product product0_
where
product0_.id=?
23:41:37- [] - ERROR[line 88] - o.e.d.ProductRepositoryTest - product=p-1
23:41:37- [] - ERROR[line 90] - o.e.d.ProductRepositoryTest - product1=p-1