一贿讹、Spring Data JPA概述
- Java持久性API(JPA)是Java的一個(gè)規(guī)范。 它用于在Java對(duì)象和關(guān)系數(shù)據(jù)庫之間保存數(shù)據(jù)够掠。 JPA充當(dāng)面向?qū)ο蟮念I(lǐng)域模型和關(guān)系數(shù)據(jù)庫系統(tǒng)之間的橋梁民褂。
- 由于JPA只是一個(gè)規(guī)范,它本身不執(zhí)行任何操作。 它需要一個(gè)實(shí)現(xiàn)赊堪。 因此面殖,像Hibernate,TopLink和iBatis這樣的ORM工具實(shí)現(xiàn)了JPA數(shù)據(jù)持久性規(guī)范哭廉。
- Spring Data是Spring Framework的一部分脊僚。Spring Data存儲(chǔ)庫抽象的目標(biāo)是顯著減少為各種持久性存儲(chǔ)實(shí)現(xiàn)數(shù)據(jù)訪問層所需的代碼量。
- Spring Data JPA不是JPA提供者遵绰。它是一個(gè)庫/框架辽幌,它在我們的JPA提供程序(如Hibernate)的頂部添加了一個(gè)額外的抽象層.其致力于減少數(shù)據(jù)訪問層(DAO)的開發(fā)量,開發(fā)者唯一要做的椿访,就只是聲明持久層的接口舶衬,其他都交給Spring Data JPA來完成。
二赎离、Spring Data JPA正向工程
- 正向工程與逆向工程相反逛犹,即通過entity實(shí)體類生成數(shù)據(jù)庫。
-
pom.xml
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.28</version> </dependency> <!-- 添加spring-data-jpa的依賴 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.11.0.RELEASE</version> </dependency> <!-- spring-data-jpa依賴于hibernate-entitymanager --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.2.10.Final</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.6.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> </dependency> </dependencies>
-
db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3307/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedSt atements=TRUE user=root pass=123456
- spring-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:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<context:property-placeholder location="classpath:db.properties" />
<context:component-scan base-package="com.qfedu.service" />
<context:component-scan base-package="com.qfedu.dao" />
<bean id="ds" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${url}" />
<property name="driverClassName" value="${driver}" />
<property name="username" value="${aaa}" />
<property name="password" value="${bbb}" />
</bean>
<!-- 配置 HibernateJpaVendorAdapter梁剔,用來分別設(shè)置數(shù)據(jù)庫的方言和是否顯示sql語句 -->
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="adapter">
<!--<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQL57InnoDBDialect" />
<property name="showSql" value="true" />
</bean>
<!-- 配置EntityManagerFactoryBean -->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emf">
<property name="dataSource" ref="ds" />
<property name="packagesToScan" value="com.qfedu.entity" />
<property name="jpaVendorAdapter" ref="adapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<!--<prop key="hibernate.dialect.storage_engine">innodb</prop>-->
<!-- 使用hibernate.hbm2ddl.auto屬性來根據(jù)需要?jiǎng)討B(tài)創(chuàng)建數(shù)據(jù)庫的表結(jié)構(gòu)
create:表示啟動(dòng)的時(shí)候先drop虽画,再create
create-drop: 也表示創(chuàng)建,只不過再系統(tǒng)關(guān)閉前執(zhí)行一下drop
update: 這個(gè)操作啟動(dòng)的時(shí)候會(huì)去檢查schema是否一致荣病,如果不一致會(huì)做scheme更新
validate: 啟動(dòng)時(shí)驗(yàn)證現(xiàn)有schema與你配置的hibernate是否一致码撰,如果不一致就拋出異常,并不做更新 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 配置jpa的事務(wù)管理器 -->
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="jtx">
<property name="entityManagerFactory" ref="emf" />
</bean>
<!-- 配置事務(wù)的注解驅(qū)動(dòng) -->
<tx:annotation-driven proxy-target-class="false" transaction-manager="jtx" />
<jpa:repositories base-package="com.qfedu.dao" entity-manager-factory-ref="emf" transaction-manager-ref="jtx" />
</beans>
- <prop key="hibernate.hbm2ddl.auto">update</prop>的作用是幫我們創(chuàng)建數(shù)據(jù)庫个盆。除了update還有三個(gè)值:
- validate:加載hibernate時(shí)脖岛,驗(yàn)證創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu)
- create:每次加載hibernate,重新創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu)颊亮,這就是導(dǎo)致數(shù)據(jù)庫表數(shù)據(jù)丟失的原因柴梆。
- create-drop:加載hibernate時(shí)創(chuàng)建,退出時(shí)刪除表結(jié)構(gòu)
- update:加載hibernate自動(dòng)更新數(shù)據(jù)庫結(jié)構(gòu)
- 實(shí)際開發(fā)中一般常用validate與update终惑。
三绍在、條件查詢
-
Emp.java
@Data @Entity @Table(name = "tbl_emp") public class Emp { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "eid") private int eid; /** * Column注解的各個(gè)屬性值說明: * name用來指定該屬性所對(duì)應(yīng)的列名,默認(rèn)與屬性名一致 * unique為true代表該屬性生成的字段唯一雹有,默認(rèn)不唯一 * nullable為false不允許為空偿渡,默認(rèn)運(yùn)行為空 * length可以給字段指定長度,默認(rèn)為255 */ @Column(name = "first_name", unique = true, nullable = false, length = 20) private String firstName; @Column(name = "last_name") private String lastName; private double salary; }
-
IEmpDao.java
@Repository public interface IEmpDao extends JpaRepository<Emp, Serializable> { List<Emp> findByFirstName(String firstName); List<Emp> findByLastNameAndFirstName(String lastName, String firstName); List<Emp> findByLastNameOrFirstName(String lastName, String firstName); List<Emp> findBySalaryBetween(double min, double max); List<Emp> findBySalaryGreaterThan(double salary); List<Emp> findByFirstNameLike(String first); List<Emp> findByLastNameOrderBySalary(String lastName); }
雖然 JPA 給我們封裝好了數(shù)據(jù)庫查詢的很多方法霸奕,不需要我們手動(dòng)書寫sql語句溜宽,但是方法名有一定的規(guī)范,方法名findBy后面是必須跟屬性名相同,第一個(gè)屬性的字母不區(qū)分大小寫质帅,后面的單詞首字母要區(qū)分大小寫适揉『衔洌可以添加的關(guān)鍵字有And、Or涡扼、Like、GreaterThan盟庞、LessThan吃沪、Between、OrderBy什猖、Asc票彪、Desc、In等不狮。使用模糊查詢Like需要在字符串前后都拼接%降铸。
-
EmpServiceImpl.java
@Service public class EmpServiceImpl implements IEmpService { JpaSpecificationExecutor d; @Resource private IEmpDao empDao; @Override public void saveEmp(Emp e) { empDao.saveAndFlush(e); } @Override public List<Emp> getEmpByFirstName(String firstname) { return empDao.findByFirstName(firstname); } @Override public List<Emp> getEmpByLastNameAndFirstName(String lastName, String firstname) { return empDao.findByLastNameAndFirstName(lastName, firstname); } @Override public List<Emp> getEmpByLastNameOrFirstName(String lastName, String firstname) { return empDao.findByLastNameOrFirstName(lastName, firstname); } @Override public List<Emp> getEmpBySalaryRange(double min, double max) { return empDao.findBySalaryBetween(min, max); } @Override public List<Emp> getEmpBySalaryGreater(double salary) { return empDao.findBySalaryGreaterThan(salary); } @Override public List<Emp> getEmpByFirstNameLike(String firstName) { return empDao.findByFirstNameLike(firstName); } @Override public List<Emp> findByLastNameOrderBySalary(String lastName) { return empDao.findByLastNameOrderBySalary(lastName); } @Override public Page<Emp> findAll(Pageable pageable) { return empDao.findAll(pageable); } }
-
EmpServiceTest.java
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring-jpa.xml") public class EmpServiceTest { @Resource private IEmpService empService; @Test public void testSaveEmp(){ Emp e = new Emp(); e.setFirstName("XXX"); e.setLastName("XX"); e.setSalary(8888); empService.saveEmp(e); } @Test public void testGetEmpsByFirstName(){ for (Emp emp : empService.getEmpByFirstName("CCC")) { System.out.println(emp); } } @Test public void testGetEmpsByLastNameAndFirstName(){ for (Emp e : empService.getEmpByLastNameOrFirstName("BBB", "BB")) { System.out.println(e); } } @Test public void testGetEmpBySalaryRange(){ for (Emp emp : empService.getEmpBySalaryRange(20000, 10000)) { System.out.println(emp); } } @Test public void testGetEmpBySalaryGreaterThan(){ for (Emp e : empService.getEmpBySalaryGreater(10000)) { System.out.println(e); } } @Test public void testGetEmpsByLike(){ String firstName = "n"; for (Emp emp : empService.getEmpByFirstNameLike("%" + firstName + "%")) { System.out.println(emp); } } @Test public void findByFirstNameOrderBySalary(){ for (Emp e : empService.findByLastNameOrderBySalary("AAA")) { System.out.println(e); } } @Test public void testGetEmpsByPage(){ Pageable pageable = new PageRequest(2, 2); Page<Emp> page = empService.findAll(pageable); List<Emp> list = page.getContent(); for (Emp e : list) { System.out.println(e); } } }
分頁查詢首先得到的結(jié)果是一個(gè)Page集合,然后返回的content是List集合摇零。