行吧,爬虫学了一点点了。先等等,把这欠着的SpringData和JPA整合篇写了。说真的这个确实是好用,手下有个小项目这次就打算用SSSP这么一套框架整合来写。我们先简单谈谈SpringData和JPA整合的基本用法。
1、创建Maven项目
这次用流行的Maven来构建项目,包管理起来比较的方便。然后把基本的包创建好,最后结构如下。
pom中的包如下,需要注意的是版本一定要对应,用eclipse我并不会看maven依赖关系,用idea可以清晰的看到包之间的依赖关系,因为用了eclipse,就不截图看了
2、编写配置文件
因为这里只测试持久层所以就不去配置SpringMVC了。
- spring配置
...
<context:property-placeholder location="classpath:jdbc.properties"/>
<context:component-scan base-package="cn.lkangle.*"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pass}"/>
</bean>
<!-- 配置entityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
</property>
<property name="packagesToScan" value="cn.lkangle.entity"/>
<!-- 配置二级缓存开启方式 -->
<property name="sharedCacheMode" value="ENABLE_SELECTIVE"/>
<property name="jpaProperties">
<props>
<!-- hibernate相关配置 -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL55Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<!-- 配置二级缓存项 -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
<!-- 配置JPA事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!-- 开启注解式事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 引入springdata jpa的支持 -->
<jpa:repositories base-package="cn.lkangle.repository" entity-manager-factory-ref="entityManagerFactory"/>
...
- 加入缓存ehcache配置
直接导入默认配置使用就行,具体怎么找我在上篇文章中已经写了。
3、编写测试类进行测试
直接一张图解决吧,这里使用了spring提供的test包。需要注意junit版本要在4.5已上。好像就4.5记不太清楚了、、、
4、超级简单的Dao层
只需要我们继承SpringDataJpa提供的各种接口就行,甚至可以不需要任何代码就能完成基本的数据库操作。springdata一共提供了四个基础接口来给我们使用
-
org.springframework.data.repository.Repository
最基础的接口,没有任何方法 -
org.springframework.data.repository.CrudRepository
为我们默认提供了一套CRUD操作的基本方法 -
org.springframework.data.repository.PagingAndSortingRepository
在CRUD的基础上提供分页和排序操作方法 -
org.springframework.data.jpa.repository.JpaRepository
继承上一个接口,包括已上所有方法。
除了一上四个比较基础的接口外还提供了一个用来动态查询的接口
-
org.springframework.data.jpa.repository.JpaSpecificationExecutor
该接口允许我们很方便的构建出支持动态查询的方法
一般我们直接继承JpaRepository
这个接口便能完成常用的CRUD操作。
save 保存,delete删除,saveAndFlush修改,findOne查找一个,findAll查找所有等等。
- 增删改查实例
@Test // 保存 public void testSave() { Clazz clazz = new Clazz(); clazz.setDate(new Date()); clazz.setName("计科一班"); Clazz clz = cdao.save(clazz); // 保存后将返回一个被jpa管理的实例,即持久化实例 Student student = new Student(); student.setDate(new Date()); student.setName("李某某"); student.setPasswd("123456"); student.setClazz(clz); sdao.save(student); } /** * 删除,这里需要注意的是,class被设置了外键,不能直接进行删除 * 需要先解除外键关联,或者设置级联删除才能正常删除 * @date 2018年3月16日 */ @Test public void testDelete() { // 直接根据id删除 cdao.delete(1); // 删除持久化对象 Clazz clz = cdao.findOne(2); cdao.delete(clz); } /** * 修改操作 需要开启事务 * @date 2018年3月16日 */ @Test public void testChange() { // 通过持久化实例的特性直接修改 ss.change(3, "张三"); } // service层代码,因为涉及到修改,这是一个事务操作,必须要开启事务才行 @Transactional public void change(Integer id, String name) { Student stu = dao.findOne(id); stu.setName(name); } @Transactional public void change(Integer id) { // 使用saveAndFlush 方法修改,需要注意的是必须每个属性都有值,不然默认空 主键是必须的 Student student = new Student(); student.setId(id); student.setDate(new Date()); student.setName("李一"); student.setPasswd("13212313"); dao.saveAndFlush(student); } /** * 简单的查询 * @date 2018年3月16日 */ @Test public void testFetch() { Student stu = sdao.findOne(3); System.out.println(stu.getName()); List<Student> stus = sdao.findAll(); System.out.println(stus.size()); }
已上是接口提供的crud基本方法,我们还能通过@Query
注解和@Modifying
注解配合使用通过JPQL
进行crud操作。
/**
* 删除
* @date 2018年3月16日
*/
@Modifying
@Query("delete from Student where id=?1")
Integer delete_(Integer id);
/**
* 修改
* @date 2018年3月16日
*/
@Modifying
@Query("update from Student set name=?1 where id=?2")
Integer change_(String name, Integer id);
/**
* 查询
* @date 2018年3月16日
*/
@Query("select s from Student s where id=?1")
Student find_(Integer id);
不仅如此SpringData JPA
还提供了根据方法名自动构建查询的功能。具体查看官方文档这里就不做示例了。
- 动态查询
对于分页查询和动态查询,SpringData JPA
也提供了全面的支持,通过继承JpaSpecificationExecutor
接口就能轻松实现。
@Transactional(readOnly = true)
public Page<Student> pageQuery(Map<String, Object> map, Integer pageNo) {
Specification<Student> spec = new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> ps = new ArrayList<>();
map.forEach((key, val)->{
try {
ps.add(cb.equal(root.get(key), val));
} catch (Exception e) {
log.error("不存在的属性--> {}", e);
}
});
query.where(ps.toArray(new Predicate[ps.size()]));
return null;
}
};
/**
* 这里我们按照id降序,每页5条数据进行分页查询
* 需要注意这里的pageNo是从0开始的
*/
Pageable sort = new PageRequest(pageNo - 1, 5, new Sort(new Sort.Order(Direction.DESC, "id")));
Page<Student> stus = dao.findAll(spec, sort);
return stus;
}
这样就简单的构建了一个动态分页查询,更多的查询条件可以在文档中查看,直接查看CriteriaQuery
和CriteriaBuilder
接口源码也能看到。
5、缓存使用也变得简单
-
根据配置,这里我们需要在被缓存的实体类上添加
@Cacheable
注解,注意要是JPA的注解
修改dao层,支持缓存
还记得上篇文章写的,在使用EntityManager
来查询时只需要在实体类上加上注解就行,这里也是这样,直接使用接口中提供的方法也是直接加上注解就行。只是那四个标准接口,分页查询动态查询的就不行了,这里要怎么配置我还不太会、、、
先写一下自定义方法的缓存配置
/**
* 查询
* @date 2018年3月16日
* @QueryHints是org.springframework.data.jpa.repository.QueryHints
* @QueryHint是javax.persistence.QueryHint
*/
@Query("select s from Student s where id=?1")
@QueryHints(@QueryHint(name = org.hibernate.jpa.QueryHints.HINT_CACHEABLE, value = "true"))
Student find_(Integer id);
6、总结
使用SpringData JPA可以简化dao层的开发,使开发者只写少量的代码就能完成复杂的数据库操作,大大加快了开发效率。官方文档链接前面加了,这里在添加一次。官方文档