一、Spring Data JPA概述
- Java持久性API(JPA)是Java的一个规范。 它用于在Java对象和关系数据库之间保存数据。 JPA充当面向对象的领域模型和关系数据库系统之间的桥梁。
- 由于JPA只是一个规范,它本身不执行任何操作。 它需要一个实现。 因此,像Hibernate,TopLink和iBatis这样的ORM工具实现了JPA数据持久性规范。
- Spring Data是Spring Framework的一部分。Spring Data存储库抽象的目标是显著减少为各种持久性存储实现数据访问层所需的代码量。
- Spring Data JPA不是JPA提供者。它是一个库/框架,它在我们的JPA提供程序(如Hibernate)的顶部添加了一个额外的抽象层.其致力于减少数据访问层(DAO)的开发量,开发者唯一要做的,就只是声明持久层的接口,其他都交给Spring Data JPA来完成。
二、Spring Data JPA正向工程
- 正向工程与逆向工程相反,即通过entity实体类生成数据库。
-
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,用来分别设置数据库的方言和是否显示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属性来根据需要动态创建数据库的表结构
create:表示启动的时候先drop,再create
create-drop: 也表示创建,只不过再系统关闭前执行一下drop
update: 这个操作启动的时候会去检查schema是否一致,如果不一致会做scheme更新
validate: 启动时验证现有schema与你配置的hibernate是否一致,如果不一致就抛出异常,并不做更新 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 配置jpa的事务管理器 -->
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="jtx">
<property name="entityManagerFactory" ref="emf" />
</bean>
<!-- 配置事务的注解驱动 -->
<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>的作用是帮我们创建数据库。除了update还有三个值:
- validate:加载hibernate时,验证创建数据库表结构
- create:每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
- create-drop:加载hibernate时创建,退出时删除表结构
- update:加载hibernate自动更新数据库结构
- 实际开发中一般常用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注解的各个属性值说明: * name用来指定该属性所对应的列名,默认与属性名一致 * unique为true代表该属性生成的字段唯一,默认不唯一 * nullable为false不允许为空,默认运行为空 * length可以给字段指定长度,默认为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 给我们封装好了数据库查询的很多方法,不需要我们手动书写sql语句,但是方法名有一定的规范,方法名findBy后面是必须跟属性名相同,第一个属性的字母不区分大小写,后面的单词首字母要区分大小写。可以添加的关键字有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); } } }
-
分页查询首先得到的结果是一个Page集合,然后返回的content是List集合。
网友评论