SpringDataJpa是 JPA規範的一個很好的實現,簡化了開發的複雜度,極大提高了開發的效率。SpringDataJpa經過 Repository接口及子接口能夠很方便的實現持久化操做。java
SpringDataJpa的API在線手冊:https://docs.spring.io/spring-data/jpa/docs/2.1.0.RELEASE/api/mysql
簡單的看下 Repository 類層次結構圖關係:web
Repository:空的父接口,便是一個標記接口。spring
CrudRepository:Repository的子接口,提供CRUD操做sql
PagingAndSortingRepository:CrudRepository的子接口,增長 分頁 和 排序的功能json
JpaRepository:PagingAndSortingRepository、QueryByExampleExecutor的子接口,增長 批量操做 以及 QBE查詢api
SimpleJpaRepository:實現了JpaRepository 和 JpaSpecificationExecutor 接口,構造函數中傳入 EntityManager。類上註解了@Transactional(readOnly = true),對於CUD的方法使用了註解@Transactional,局部有限原則。各類方法最終的實現都依託於 EntityManager來完成。springboot
一、建立springboot項目 springdata-jpaapp
二、src/main/resources 目錄下新建 application.properties,內容以下:dom
db.driverClass=com.mysql.jdbc.Driver db.jdbcUrl=jdbc:mysql://localhost:3310/boot?useUnicode=true&characterEncoding=UTF-8&useSSL=false db.username=root db.password=123456 spring.jpa.properties.hibernate.show_sql=true spring.jpa.properties.hibernate.format_sql=true #修改實體類的匹配命名規則,主要影響@column(name="")配置,默認是駝峯匹配法 spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
三、建立 DataSource configuration:
package com.cfang.confingurations; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.alibaba.druid.pool.DruidDataSource; @Configuration public class DataSourceConfigurations { @Value("${db.driverClass:com.mysql.jdbc.Driver}") private String driverClass; @Value("${db.jdbcUrl}") private String jdbcUrl; @Value("${db.username}") private String username; @Value("${db.password}") private String password; @Value("${initialSize:10}") private Integer initialSize; //初始化鏈接池個數 @Value("${maxActive:20}") private Integer maxActive; //最大鏈接數 @Value("${maxWait:60000}") private Long maxWait; //獲取鏈接等待超時時間,單位毫秒 @Value("${timeBetweenEvictionRunsMillis:60000}") private Long timeBetweenEvictionRunsMillis; //間隔多久進行一次檢測,檢測回收須要關閉的空閒連接,單位毫秒 @Value("${minEvictableIdleTimeMillis:300000}") private Long minEvictableIdleTimeMillis; //定義一個鏈接在池中的最小生存時間,單位毫秒 @Value("${validationQuery:select 1 from dual}") private String validationQuery; //用來檢測鏈接是否有效的sql @Value("${testWhileIdle:true}") private Boolean testWhileIdle; //申請鏈接的時候是否檢測。若是空間時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測鏈接是否有效 @Value("${testOnBorrow:false}") private Boolean testOnBorrow; @Value("${testOnReturn:false}") private Boolean testOnReturn; //歸還鏈接的時候,是否validationQuery檢查鏈接的有效性,true執行的話,下降性能 @Value("${poolPreparedStatements:false}") private Boolean poolPreparedStatements; //是否打開pscache @Value("${maxPoolPreparedStatementPerConnectionSize:20}") private int maxPoolPreparedStatementPerConnectionSize; //指定每一個鏈接的pscache的大小 @Bean public DataSource initDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driverClass); dataSource.setUrl(jdbcUrl); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setInitialSize(initialSize); dataSource.setMaxActive(maxActive); dataSource.setMaxWait(maxWait); dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); dataSource.setValidationQuery(validationQuery); dataSource.setTestWhileIdle(testWhileIdle); dataSource.setTestOnBorrow(testOnBorrow); dataSource.setTestOnReturn(testOnReturn); dataSource.setPoolPreparedStatements(poolPreparedStatements); if(poolPreparedStatements) { dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); } return dataSource; } }
四、建立User實體
package com.cfang.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.Data; @Entity @Table(name = "tb_user") @Data public class TblUserEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "name") private String name; @Column(name = "password") private String password; @Column(name = "age") private int age; }
五、建立持久化操做Repository:
package com.cfang.repository; import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import com.cfang.entity.TblUserEntity; public interface UserRepository extends JpaRepository<TblUserEntity, Integer>, JpaSpecificationExecutor<TblUserEntity>{ /** * springdata關鍵字命名方法,可不寫實現 */ TblUserEntity findByName(String name); TblUserEntity findByNameAndAge(String name, int age); List<TblUserEntity> findByNameLikeAndAge(String name, int age); Page<TblUserEntity> findUserPageByNameLike(String name, Pageable pageable); /** * JPQL */ @Query(value = "from TblUserEntity where id=?1", nativeQuery = false) TblUserEntity readIdByJPQL(int id); @Query(value = "select * from tb_user where id=:id", nativeQuery = true) TblUserEntity readIdBySQL(int id); @Modifying @Query(value = "update TblUserEntity set name=?2 where id=?1", nativeQuery = false) int updateUserNameByIdJPQL(int id, String name); @Modifying @Query(value = "update tb_user set name=:name where id=:id", nativeQuery = true) int updateUserNameByIdSQL(@Param("id")int id, @Param("name")String name); @Query(value = "from TblUserEntity where name like %?1%", nativeQuery = false) List<TblUserEntity> findUserByNameJPQL(String name); @Query(value = "select * from tb_user where name like %:name%", nativeQuery = true) List<TblUserEntity> findUserByNameSQL(String name); }
六、建立 junit 測試
package com.cfang.repository; import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.transaction.annotation.Transactional; import com.alibaba.fastjson.JSON; import com.cfang.SpringDataJpaApplication; import com.cfang.entity.TblUserEntity; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; @Slf4j @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = {SpringDataJpaApplication.class}) @WebAppConfiguration public class UserTest { @Autowired private UserRepository userRepository; @Test public void findByName() { TblUserEntity entity = userRepository.findByName("lisi"); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void findByNameAndAge() { TblUserEntity entity = userRepository.findByNameAndAge("lisi", 22); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void findByNameLikeAndAge() { List<TblUserEntity> entity = userRepository.findByNameLikeAndAge("li%", 22); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void readIdByJPQL() { TblUserEntity entity = userRepository.readIdByJPQL(27); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void readIdBySQL() { TblUserEntity entity = userRepository.readIdBySQL(27); log.info("result:{}", JSON.toJSONString(entity)); } @Test @Transactional @Rollback(false) public void updateUserNameByIdJPQL() { int result = userRepository.updateUserNameByIdJPQL(27, "wangwu"); log.info("result:{}", result); } @Test @Transactional @Rollback(false) public void updateUserNameByIdSQL() { int result = userRepository.updateUserNameByIdSQL(27, "wangwu2"); log.info("result:{}", result); } @Test public void findUserByNameJPQL() { List<TblUserEntity> entity = userRepository.findUserByNameJPQL("li"); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void findUserByNameSQL() { List<TblUserEntity> entity = userRepository.findUserByNameSQL("li"); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void findUserPageByNameLike() { Pageable pageable = PageRequest.of(0, 2, new Sort(Sort.Direction.DESC, "id")); Page<TblUserEntity> entity = userRepository.findUserPageByNameLike("li%", pageable); log.info("result:{}", JSON.toJSONString(entity)); } @Test public void testSpecification() { Pageable pageable = PageRequest.of(0, 2, Sort.Direction.DESC, "id"); String name = "li"; Specification<TblUserEntity> specification = new Specification<TblUserEntity>() { @Override public Predicate toPredicate(Root<TblUserEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { List<Predicate> conditions = Lists.newArrayList(); Predicate condition = null; condition = criteriaBuilder.like(root.get("name"), "%" + name + "%"); conditions.add(condition); condition = criteriaBuilder.greaterThan(root.get("id"), 27); conditions.add(condition); Predicate[] arr = new Predicate[conditions.size()]; // return criteriaBuilder.and(conditions.toArray(arr)); query.where(conditions.toArray(arr)); return null; } }; Page<TblUserEntity> result = userRepository.findAll(specification, pageable); log.info("result:{}", JSON.toJSONString(result)); } }
ps:在進行 repository 的CUD操做的時候,必須加事務支持 @Transactional,不然會報錯(截取部分出錯信息):
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
數據進行持久化操做的時候,都是須要一個對象來進行相關操做的,原生的Hibernate中使用Session,JPA中使用EntityManager,MyBatis中使用SqlSession。上述工程中,在主類main方法中可添加以下進行查看:
@Bean public Object testTransactionManager(PlatformTransactionManager manager) { System.out.println("TransactionManager is : " + manager.getClass().getName()); return new Object(); }
SpringDataJpa提供了豐富的CRUD構造的方法,具體可根據實際狀況查詢使用。