JPA一:理论知识和入门程序

1 概述

  1. JPA的全称是Java Persistence API, 即Java持久化API,内部是由一系列的接口和抽象类构成。

  2. JPA优势

    1. 标准化:JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
    2. 容器级特性的支持:JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
    3. 简单方便:JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity 进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成
    4. 查询能力:JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
    5. 高级特性:JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。
  3. JPA 和 Hibernate 关系

    1. JPA规范本质上就是一种ORM规范,注意不是ORM框架,因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。

    2. JPA 和 Hibernate 的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现

    3. 图解

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXoZ6hdl-1641474572546)(assets/image-20220106145026254.png)]

2 Hibernate 增删改查

  • 下面例子主要讲 JPA 基于 Hibernate 方式实现增删改查。下面会讲 Spring Data JPA,这个才是学习的重点。但 Hibernate 和 Spring Data JPA 类似,因此可以了解下 Hibernate。

  • 常用注解说明

    注解说明属性说明
    @Entity指定当前类是实体类
    (一般情况下,实体类属性与数据库字段一一对应)
    @Table指定实体类和表之间的对应关系name 属性用于指定表名
    @Id指定当前字段是主键
    @GeneratedValue指定主键的生成方式strategy 属性用于指定主键生成策略
    @Column指定实体类属性和数据库表之间的对应关系name 指定数据库表的列名称
    unique 是否唯一
    nullable 是否可以为空
    insertable 是否可以插入
    updateable 是否可以更新
    columnDefinition 定义建表时创建此列的DDL
    @SecondaryTable从表名

项目搭建

  • SQL脚本

    CREATE TABLE `t_users`(
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(64) NOT NULL DEFAULT '',
      `gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1 male,2 female',
      `age` int(11) NOT NULL DEFAULT '0',
      `telphone` varchar(255) NOT NULL DEFAULT '',
      `register_mode` varchar(255) NOT NULL DEFAULT '' COMMENT 'byphone,bywechat,byalipay',
      PRIMARY KEY (`id`),
      UNIQUE KEY `telphone_unique_index` (`telphone`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
    
    INSERT INTO `t_users` VALUES(1,'zhangsan',1,30,'18362610001','byphone');
    INSERT INTO `t_users` VALUES(2,'lisi',1,20,'18362610002','byphone');
    INSERT INTO `t_users` VALUES(3,'wangwu',1,1,'18362610003','byphone');
    INSERT INTO `t_users` VALUES(4,'zhaoliu',1,31,'18362610004','byphone');
    INSERT INTO `t_users` VALUES(5,'xiaohong',2,20,'18362610005','byphone');
    
  • 项目结构如下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0bvKWYXW-1641474572547)(assets/image-20220106161334905.png)]

  1. 创建普通maven工程,并导入依赖

    <properties>
        <hibernate.version>5.5.9.Final</hibernate.version>
        <log4j.version>1.2.17</log4j.version>
        <mysql.version>8.0.21</mysql.version>
        <junit.version>4.13</junit.version>
        <lombok.version>1.18.12</lombok.version>
    </properties>
    <dependencies>
        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <!-- c3p0 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
    </dependencies>
    
  2. 配置文件

    • resources/META-INF/persistence.xml ,手动创建 META-INF 目录,必须为该路径、否则找不到配置文件!
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
        <!-- 配置持久化单元格,transaction-type="RESOURCE_LOCAL"即本地事务管理,若改为JTA代表分布式事务管理-->
        <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
            <!--jpa的实现方式(由hibernate实现) -->
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
            <properties>
                <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="javax.persistence.jdbc.url"
                          value="jdbc:mysql://192.168.181.160:3306/test?serverTimezone=CTT"/>
                <property name="javax.persistence.jdbc.user" value="root"/>
                <property name="javax.persistence.jdbc.password" value="root"/>
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.hbm2ddl.auto" value="update"/>
                <!--
                    最后一行表示jpa实现方的配置信息
                    name="hibernate.hbm2ddl.auto" 表示自动创建数据库表
                    value="update" 即程序运行时创建表(如果有表,不会创建表),
                    value="create"表示程序运行时创建数据库表(如果有表,先删除表再创建)
                    value="none"表示不会创建表
                -->
            </properties>
        </persistence-unit>
    </persistence>
    
  3. 编写实体类

    package entity;
    
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    import javax.persistence.*;
    
    @Entity
    @Table(name = "t_users")
    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    public class UserEntity {
        @Id
        // 指定主键自增策略由数据库自动生成(主要是自动增长型)
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;
    
        @Column(name = "name")
        private String name;
    
        @Column(name = "gender")
        private Integer gender;
    
        @Column(name = "age")
        private Integer age;
    
        @Column(name = "telphone")
        private String telphone;
    
        @Column(name = "register_mode")
        private String registerMode;
    
        // 因为主键自增,故需要除主键外的构造函数(get、set方法用lombok注解生成)
        // 若是不要构造方法的话,set每个属性也可
        public UserEntity(String name, Integer gender, Integer age, String telphone, String registerMode) {
            this.name = name;
            this.gender = gender;
            this.age = age;
            this.telphone = telphone;
            this.registerMode = registerMode;
        }
    }
    
  4. 测试

    package test;
    
    import entity.UserEntity;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import javax.persistence.*;
    import java.util.List;
    
    public class MyTest {
        private EntityManagerFactory factory;
        private EntityManager entityManager;
        private EntityTransaction tx;
    
        @Before
        public void before() {
            /**
             * JPA 基于 Hibernate 方式实现增删改查的步骤如下
             *
             * 1.加载配置文件创建工厂(实体管理器工厂)对象
             * 注:配置文件要写在META-INF/persistence.xml下,若是直接放在resources下找不到
             * 配置文件 persistence.xml 中 name="myJpa"
             */
            factory = Persistence.createEntityManagerFactory("myJpa");
            // 2.通过实体管理器工厂获取实体管理器
            entityManager = factory.createEntityManager();
            // 3.获取事务对象
            tx = entityManager.getTransaction();
            // 4.开启事务
            tx.begin();
            // 5.完成增删改查操作(即下面的各个测试类)
        }
    
        @After
        public void after() {
            // 6.提交事务(回滚事务)
            tx.commit();
            // 7.释放资源
            entityManager.close();
            factory.close();
        }
    
        /**
         * 测试一:根据主键id进行查询
         */
        @Test
        public void test1() {
            UserEntity user = entityManager.find(UserEntity.class, 2);
            System.out.println(user);
            // UserEntity(id=2, name=lisi, gender=1, age=20, telphone=18362610002, registerMode=byphone)
        }
    
    
        /**
         * 测试二:查询所有
         * 使用JPQL语法,注意此时操作的是实体类而不是表名,
         * 因此from对象是 UserEntity 而不是 t_users
         */
        @Test
        public void test2() {
            String jpql = new String("from UserEntity");
            Query query = entityManager.createQuery(jpql);
            List list = query.getResultList();
            list.forEach(element -> System.out.println(element));
            /**
             * UserEntity(id=1, name=zhangsan, gender=1, age=30, telphone=18362610001, registerMode=byphone)
             * UserEntity(id=2, name=lisi, gender=1, age=20, telphone=18362610002, registerMode=byphone)
             * UserEntity(id=3, name=wangwu, gender=1, age=1, telphone=18362610003, registerMode=byphone)
             * UserEntity(id=4, name=zhaoliu, gender=1, age=31, telphone=18362610004, registerMode=byphone)
             * UserEntity(id=5, name=xiaohong, gender=2, age=20, telphone=18362610005, registerMode=byphone)
             */
        }
    
        /**
         * 测试三:添加
         * <p>
         * persist():持久化即保存(添加)操作
         */
        @Test
        public void test3() {
            UserEntity userEntity = new UserEntity("小明", 2, 18, "18362610009", "bywechat");
            entityManager.persist(userEntity);
        }
    
        /**
         * 测试四:删除
         * (先根据id查询账户,再删除)
         */
        @Test
        public void test4() {
            UserEntity userEntity = entityManager.find(UserEntity.class, 3);
            entityManager.remove(userEntity);
        }
    
        /**
         * 测试五:修改
         * (先查,赋新值,清缓存[可省],修改)
         */
        @Test
        public void test5() {
            UserEntity userEntity = entityManager.find(UserEntity.class, 5);
            userEntity.setName("小小红");
            entityManager.clear(); // 可省
            entityManager.merge(userEntity);
        }
    
        /**
         * 下面的查询可以看看,大部分就是换了个jpql
         * <p>
         * 测试六:分页查询
         */
        @Test
        public void test6() {
            String jpql = new String("from UserEntity");
            Query query = entityManager.createQuery(jpql);
            // 设置起始索引和每页显示条数
            query.setFirstResult(0);
            query.setMaxResults(3);
            List list = query.getResultList();
            list.forEach(element -> System.out.println(element));
            /**
             * 结果
             * UserEntity(id=1, name=zhangsan, gender=1, age=30, telphone=18362610001, registerMode=byphone)
             * UserEntity(id=2, name=lisi, gender=1, age=20, telphone=18362610002, registerMode=byphone)
             * UserEntity(id=4, name=zhaoliu, gender=1, age=31, telphone=18362610004, registerMode=byphone)
             *
             * ps:结果集的下标从0开始
             */
        }
    
        /**
         * 测试七:条件查询
         */
        @Test
        public void test7() {
            String jpql = new String("from UserEntity where name like ?1");
            Query query = entityManager.createQuery(jpql);
            // SQL中的 ?1 表示第一个参数,此处表示对第一个参数赋值
            query.setParameter(1, "%小%");
            List list = query.getResultList();
            for (Object obj : list) {
                System.out.println(obj);
            }
            /**
             * UserEntity(id=5, name=小小红, gender=2, age=20, telphone=18362610005, registerMode=byphone)
             * UserEntity(id=6, name=小明, gender=2, age=18, telphone=18362610009, registerMode=bywechat)
             */
        }
    
        /**
         * 测试八:排序查询
         */
        @Test
        public void test8() {
            String jpql = new String("from UserEntity order by id desc");
            Query query = entityManager.createQuery(jpql);
            List list = query.getResultList();
            list.forEach(e -> System.out.println(e));
            /**
             * UserEntity(id=6, name=小明, gender=2, age=18, telphone=18362610009, registerMode=bywechat)
             * UserEntity(id=5, name=小小红, gender=2, age=20, telphone=18362610005, registerMode=byphone)
             * UserEntity(id=4, name=zhaoliu, gender=1, age=31, telphone=18362610004, registerMode=byphone)
             * UserEntity(id=2, name=lisi, gender=1, age=20, telphone=18362610002, registerMode=byphone)
             * UserEntity(id=1, name=zhangsan, gender=1, age=30, telphone=18362610001, registerMode=byphone)
             */
        }
    
        /**
         * 测试九:统计个数
         * <p>
         * getSingleResult():得到唯一结果集
         */
        @Test
        public void test9() {
            String jpql = new String("select count(id) from UserEntity");
            Query query = entityManager.createQuery(jpql);
            Object count = query.getSingleResult();
            System.out.println("count = " + count);
            // count = 5
        }
    }
    

3 Spring Data JPA

3.1 概述

  • Spring Data JPAJPAHibernate 之间的关系如下
  1. JPA是一套规范,内部是由接口和抽象类组成的。
  2. Hibernate 是一套成熟的 ORM 框架,而且 Hibernate 实现了 JPA 规范,所以也可以称 Hibernate 为 JPA 的一种实现方式,我们使用 JPA 的 API 编程,意味着站在更高的角度上看待问题(面向接口编程)。
  3. Spring Data JPA 是 Spring 提供的一套对 JPA 操作更加高级的封装,是在 JPA 规范下的专门用来进行数据持久化的解决方案。

3.2 增删改查

  1. SQL脚本略,同上面的 Hibernate

    CREATE TABLE `t_users`(
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(64) NOT NULL DEFAULT '',
      `gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1 male,2 female',
      `age` int(11) NOT NULL DEFAULT '0',
      `telphone` varchar(255) NOT NULL DEFAULT '',
      `register_mode` varchar(255) NOT NULL DEFAULT '' COMMENT 'byphone,bywechat,byalipay',
      PRIMARY KEY (`id`),
      UNIQUE KEY `telphone_unique_index` (`telphone`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
    
    INSERT INTO `t_users` VALUES(1,'zhangsan',1,30,'18362610001','byphone');
    INSERT INTO `t_users` VALUES(2,'lisi',1,20,'18362610002','byphone');
    INSERT INTO `t_users` VALUES(3,'wangwu',1,1,'18362610003','byphone');
    INSERT INTO `t_users` VALUES(4,'zhaoliu',1,31,'18362610004','byphone');
    INSERT INTO `t_users` VALUES(5,'xiaohong',2,20,'18362610005','byphone');
    
  2. 项目结构如下

    在这里插入图片描述

  3. 创建普通maven工程,导入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>cn</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <!--
            1. 最新版data-jpa的版本是2.6.0,但使用该版本时,各种依赖冲突问题,尝试许久也未解决,简直要人老命~
            2. 故使用较低版本的data-jpa进行项目搭建,该项目了解即可,以后都是使用springboot项目整合jpa了
            3. 另外,本项目中连接池 c3p0 也已经废弃了,由maven官网可知,2007年以后就不在更新维护了;若是其他项目使用连接池,可用 druid连接池 代替
            4. so,该项目看看即可,若是使用原生spring整合data jpa,升级版本时会遇到各种依赖冲突问题。自己解决可太难了,现在体会到springboot项目的强大了吧?!
            -->
    
            <!-- <jpa.version>2.6.0</jpa.version> -->
            <jpa.version>1.9.0.RELEASE</jpa.version>
            <spring.version>5.2.19.RELEASE</spring.version>
            <aspectj.version>1.9.7</aspectj.version>
            <hibernate.version>5.5.9.Final</hibernate.version>
            <slf4j.version>2.0.0-alpha5</slf4j.version>
            <log4j.version>1.2.17</log4j.version>
            <c3p0.version>0.9.1.2</c3p0.version>
            <mysql.version>8.0.21</mysql.version>
            <junit.version>4.12</junit.version>
            <el.version>2.2.4</el.version>
            <lombok.version>1.18.12</lombok.version>
            <jaxb.version>3.0.2</jaxb.version>
        </properties>
    
        <dependencies>
            <!-- spring 相关依赖 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <!-- spring data 相关,引入该依赖后必需引入下面的俩 el 依赖 -->
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-jpa</artifactId>
                <version>${jpa.version}</version>
            </dependency>
            <dependency>
                <groupId>javax.el</groupId>
                <artifactId>javax.el-api</artifactId>
                <version>${el.version}</version>
            </dependency>
            <dependency>
                <groupId>org.glassfish.web</groupId>
                <artifactId>javax.el</artifactId>
                <version>${el.version}</version>
            </dependency>
    
            <!-- hibernate 依赖(data jpa 需要配合 hibernate 使用) -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <version>${hibernate.version}</version>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-entitymanager</artifactId>
                <version>${hibernate.version}</version>
            </dependency>
    
            <!-- aspectJ依赖,aop需要用到-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
    
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
    
            <!-- c3p0 连接池-->
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>${c3p0.version}</version>
            </dependency>
    
            <!-- log 依赖-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
    
            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
    
            <!-- junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <!--
        指定编译的字节码版本,自己使用的是jdk11,因此指定编译的版本为java11
        默认是java5,否则需要自己修改IDEA中的配置
        -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.6.1</version>
                    <configuration>
                        <source>11</source>
                        <target>11</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
  4. 配置文件

    <?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:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:jdbc="http://www.springframework.org/schema/jdbc"
           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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.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">
    
        <!-- 1.配置数据源 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://192.168.192.134:3306/test?serverTimezone=CTT"/>
            <property name="user" value="root"/>
            <property name="password" value="root"/>
        </bean>
    
        <!-- 2.配置entityManagerFactory,并把它交给spring容器管理-->
        <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <!--配置的扫描的包(实体类所在的包) -->
            <property name="packagesToScan" value="cn.entity"/>
            <!-- jpa的实现厂家 -->
            <property name="persistenceProvider">
                <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
            </property>
            <!--jpa的供应商适配器 -->
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <!--配置是否自动创建数据库表 -->
                    <property name="generateDdl" value="false"/>
                    <!--指定数据库类型 -->
                    <property name="database" value="MYSQL"/>
                    <!--数据库方言:支持的特有语法 -->
                    <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
                    <!--是否显示sql -->
                    <property name="showSql" value="true"/>
                </bean>
            </property>
            <!--jpa的方言 :高级的特性 -->
            <property name="jpaDialect">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
            </property>
        </bean>
        <!--3.配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactoty"/>
        </bean>
        <!--4.整合spring data JPA-->
        <jpa:repositories base-package="cn.repository" transaction-manager-ref="transactionManager"
                          entity-manager-factory-ref="entityManagerFactoty"/>
        <!-- 5.txAdvice-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" propagation="REQUIRED"/>
                <tx:method name="insert*" propagation="REQUIRED"/>
                <tx:method name="delete*" propagation="REQUIRED"/>
                <tx:method name="update*" propagation="REQUIRED"/>
                <tx:method name="get*" read-only="true"/>
                <tx:method name="find*" read-only="true"/>
                <tx:method name="*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <!-- 6.aop(切点定位到业务层实现类)-->
        <aop:config>
            <aop:pointcut id="pointcut" expression="execution(* cn.service.impl.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
        </aop:config>
        <!-- 7. 配置包扫描-->
        <context:component-scan base-package="cn"/>
    </beans>
    
  5. 编写实体类

    package cn.entity;
    import lombok.Data;
    import javax.persistence.*;
    
    @Entity
    @Table(name = "t_users")
    @Data
    public class UserEntity {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;
    
        @Column(name = "name")
        private String name;
    
        @Column(name = "gender")
        private Integer gender;
    
        @Column(name = "age")
        private Integer age;
    
        @Column(name = "telphone")
        private String telphone;
    
        @Column(name = "register_mode")
        private String registerMode;
    }
    
  6. 编写持久层

    package cn.repository;
    
    import cn.entity.UserEntity;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    
    public interface UserRepository extends JpaRepository<UserEntity, Integer>, JpaSpecificationExecutor<UserEntity> {
        
    }
    
  7. 测试

    package test;
    
    import cn.entity.UserEntity;
    import cn.repository.UserRepository;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import java.util.List;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:application.xml")
    public class MyTest {
        @Autowired
        private UserRepository userRepository;
    
        /**
         * 测试添加
         */
        @Test
        public void testSave() {
            UserEntity userEntity = new UserEntity();
            userEntity.setName("小明");
            userEntity.setGender(2);
            userEntity.setAge(22);
            userEntity.setTelphone("18362610009");
            userEntity.setRegisterMode("bywechat");
            userRepository.save(userEntity);
        }
    
        /**
         * 测试删除
         */
        @Test
        public void testDelete() {
            userRepository.delete(6);
        }
    
        /**
         * 测试修改
         * <p>
         * 思路
         * 1. 先根据id查实体类
         * 2. 然后修改
         * 3. 最后调用save方法更新
         * <p>
         * save方法的解释:
         * 1. id在数据库中不存在,即为插入insert
         * 2. id在数据库中已存在,即为更新update
         */
        @Test
        public void testUpdate() {
            UserEntity userEntity = userRepository.findOne(2);
    
            userEntity.setName("李小四");
            userEntity.setRegisterMode("bywechat");
            userRepository.save(userEntity);
        }
    
        /**
         * 测试查找(根据主键查)
         */
        @Test
        public void testFindOne() {
            /**
             * 注:新版 data-jpa (version=2.6.0) 版本中
             * 接口有改动,应该用 UserEntity userEntity = userRepository.getById(1);
             * 但是自己使用原生Spring整合出现依赖冲突问题,简直要人老命~~~
             * 以后使用SpringBoot时,data-jpa改成最新版本
             */
            UserEntity userEntity = userRepository.findOne(1);
            System.out.println(userEntity);
            // UserEntity(id=1, name=zhangsan, gender=1, age=30, telphone=18362610001, registerMode=byphone)
        }
    
        /**
         * 测试查找(查询所有)
         */
        @Test
        public void testFindAll() {
            List<UserEntity> users = userRepository.findAll();
            for (UserEntity user : users) {
                System.out.println(user);
            }
            /**
             * UserEntity(id=1, name=zhangsan, gender=1, age=30, telphone=18362610001, registerMode=byphone)
             * UserEntity(id=2, name=lisi, gender=1, age=20, telphone=18362610002, registerMode=byphone)
             * UserEntity(id=3, name=wangwu, gender=1, age=1, telphone=18362610003, registerMode=byphone)
             * UserEntity(id=4, name=zhaoliu, gender=1, age=31, telphone=18362610004, registerMode=byphone)
             * UserEntity(id=5, name=xiaohong, gender=2, age=20, telphone=18362610005, registerMode=byphone)
             */
        }
    }
    

IDEA 工具中,解决 “错误: 不支持发行版本 5”

  • 法一:修改项目配置

    1. File -> Project Structure -> Modules(则需修改)
    2. File -> Settings -> Build,Execution,Deployment -> Compiler -> Java Compiler -> Target bytecode version(则需修改)
  • 法二:pom文件中指定编译的字节码版本

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    

补充:SpringBoot 整合 JPA

  • 见以前博客 SpringBoot二:整合其他框架
  • 以后均用 SpringBoot 整合 JPA 使用,不再使用纯 Spring 整合 JPA,升级版本时、发生版本冲突要人老命~~~

3.3 原理

  1. 继承关系图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKCDBK4n-1641520712244)(assets/image-20220107094351029.png)]

    • 上面持久层代码 UserRepository extends JpaRepository, JpaSpecificationExecutor (或由上图也可以看出),因此在 UserRepository 接口中,没有写一行代码,却能实现增删改查等基本操作。下面将对 JpaRepositoryJpaSpecificationExecutor 这俩接口中的方法进行介绍。
  2. JpaRepository :该接口封装了基本的CURD操作

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tl2kzSz9-1641520712245)(assets/image-20220107094530272.png)]

    /**
     * 注:JpaRepository 继承 PagingAndSortingRepository,而 PagingAndSortingRepository 又继承 CrudRepository
     */
    
    // 1. JpaRepository 接口源码
    public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
        List<T> findAll();
        List<T> findAll(Sort var1);
        List<T> findAll(Iterable<ID> var1);
        <S extends T> List<S> save(Iterable<S> var1);
        void flush();
        <S extends T> S saveAndFlush(S var1);
        void deleteInBatch(Iterable<T> var1);
        void deleteAllInBatch();
        T getOne(ID var1);
    }
    
    // 2. PagingAndSortingRepository 接口源码
    public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
        Iterable<T> findAll(Sort var1);
        Page<T> findAll(Pageable var1);
    }
    
    // 3. CrudRepository 接口源码
    public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
        <S extends T> S save(S var1);
        <S extends T> Iterable<S> save(Iterable<S> var1);
        T findOne(ID var1);
        boolean exists(ID var1);
        Iterable<T> findAll();
        Iterable<T> findAll(Iterable<ID> var1);
        long count();
        void delete(ID var1);
        void delete(T var1);
        void delete(Iterable<? extends T> var1);
        void deleteAll();
    }
    
  3. JpaSpecificationExecutor :该接口封装了复杂的查询(如分页查询、动态SQL查询)等 【动态SQL是重点,后面会单独写文章介绍用法】

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oNGuy8b-1641520712245)(assets/image-20220107094937164.png)]

    public interface JpaSpecificationExecutor<T> {
        T findOne(Specification<T> var1);
        List<T> findAll(Specification<T> var1);
        Page<T> findAll(Specification<T> var1, Pageable var2);
        List<T> findAll(Specification<T> var1, Sort var2);
        long count(Specification<T> var1);
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值