spring-mvc-demo
JPA Spring Data
1、致力于减少数据访问层的开发量。
2、开发者唯一要做的,就是声明持久层接口 其他都交给Spring data JPA完成
3、框架怎么可能代替开发者实现业
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
<version>2.2.4.RELEASEversion>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-coreartifactId>
<version>5.2.17.Finalversion>
dependency>
数据源配置可以放在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.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
<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">
<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>
<property name="packagesToScan" value="org.example.demo.jpa.entity"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.implicit_naming_strategy">
org.hibernate.boot.model.naming.SpringImplicitNamingStrategy
prop>
<prop key="hibernate.physical_naming_strategy">
org.hibernate.boot.model.naming.SpringPhysicalNamingStrategy
prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialectprop>
<prop key="hibernate.show_sql">trueprop>
<prop key="hibernate.format_sql">trueprop>
<prop key="hibernate.hbm2ddl.auto">createprop>
props>
property>
bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<jpa:repositories base-package="org.example.demo.jpa.repository"
entity-manager-factory-ref="entityManagerFactory">
jpa:repositories>
beans>
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);
}
}
// 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> {
}
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-ehcacheartifactId>
<version>5.2.17.Finalversion>
dependency>
<property name="jpaProperties">
<props>
......
<prop key="hibernate.use_second_level_cache">trueprop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactoryprop>
<prop key="hibernate.cache.use_query_cache">trueprop>
<prop key="net.sf.ehcache.configurationResourceName">ehcache.xmlprop>
props>
property>
将该文件放在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>
@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
spring-mvc-jpa-demo