Spring Data JPA

一、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集合。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,601评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,367评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,249评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,539评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,967评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,929评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,098评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,825评论 0 207
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,609评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,796评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,282评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,603评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,277评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,159评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,959评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,079评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,874评论 2 277

推荐阅读更多精彩内容