IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring与SpringBoot整合Spring Data JPA及使用 -> 正文阅读

[Java知识库]Spring与SpringBoot整合Spring Data JPA及使用

本节由浅入深,再浅出学习Spring data JPA。我的学习路程是先通过spring整合Spring data JPA来具体学习,逐渐深入,学习完这些重要知识点后,再浅出到使用SpringBoot来整合Spring data JPA。

一.Spring整合Spring Data JPA

Spring Data JPA是Spring Data项目下的一个模块。提供了一套基于JPA标准操作数据库的简化方案,底层默认是依赖Hibernate JPA来实现的。

Spring Data JPA的技术特点:我们只需要定义接口并继承Spring Data JPA中所提供的接口就可以了。不需要编写接口实现类。

1.创建Spring Data JPA的项目,导入依赖,编写配置文件

    <dependencies>
    <!--Spring Ioc相关依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.18</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.18</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.18</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>5.3.18</version>
    </dependency>

    <!--Spring Aop的相关依赖-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.8.RC2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.18</version>
    </dependency>

    <!--Spring jdbc的相关依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.18</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.3.18</version>
    </dependency>

    <!--spring orm的相关依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>5.3.18</version>
    </dependency>

    <!--单元测试用的依赖-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.18</version>
    </dependency>

    <!--日志依赖-->
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>

    <!--Hibernate的核心依赖,9个必须要导入-->
    <!-- https://mvnrepository.com/artifact/antlr/antlr -->
    <dependency>
        <groupId>antlr</groupId>
        <artifactId>antlr</artifactId>
        <version>2.7.7</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.geronimo.specs/geronimo-jta_1.1_spec -->
    <dependency>
        <groupId>org.apache.geronimo.specs</groupId>
        <artifactId>geronimo-jta_1.1_spec</artifactId>
        <version>1.1.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate.common/hibernate-commons-annotations -->
    <dependency>
        <groupId>org.hibernate.common</groupId>
        <artifactId>hibernate-commons-annotations</artifactId>
        <version>5.1.2.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.5.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.1-api</artifactId>
        <version>1.0.0.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.jboss/jandex -->
    <dependency>
        <groupId>org.jboss</groupId>
        <artifactId>jandex</artifactId>
        <version>2.0.0.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.28.0-GA</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
    <dependency>
        <groupId>org.jboss.logging</groupId>
        <artifactId>jboss-logging</artifactId>
        <version>3.4.1.Final</version>
    </dependency>

    <!--mysql数据驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>

    <!--连接池相关的依赖-->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.5</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>5.6.7.Final</version>
    </dependency>

    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>mchange-commons-java</artifactId>
        <version>0.2.19</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.6.7.Final</version>
    </dependency>

    <!--Spring Data JPA的相关依赖-->

    <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
        <version>2.6.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.6.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.36</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.28</version>
    </dependency>

</dependencies>

applicationContext.xml相比之前spring整合Hibernate JPA时多了一个jpa的命名空间,其他也不用删除先,然后添加一个jpa的dao扫描,具体配置如下:

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa
        https://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置读取properties文件的工具类-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--配置c3p0数据库连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="driverClass" value="${jdbc.driver.class}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--Spring整合 Hibernate JPA ,配置EntityManagerFactory-->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--hibernate相关属性的注入:-->
                <!--database配置数据库类型-->
                <property name="database" value="MYSQL"/>
                <!--开启正向工程,自动创建表-->
                <property name="generateDdl" value="true"/>
                <!--开启显示执行的sql-->
                <property name="showSql" value="true"/>
            </bean>
        </property>
        <!--配置要扫描的实体的包-->
        <property name="packagesToScan">
            <list>
                <value>com.haiexijun.pojo</value>
            </list>
        </property>
    </bean>

    <!--配置Hibernate的事务管理器-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>


    <!--开启注解事务处理-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!--配置springIOC的注解扫描-->
    <context:component-scan base-package="com.haiexijun"/>

    <!--Spring Data JPA的配置-->
    <!--base-package:扫描dao接口所在的包-->
    <jpa:repositories base-package="com.haiexijun.dao" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>

</beans>

jdbc.properties

jdbc.url=jdbc:mysql://localhost:3306/hibernate02
jdbc.driver.class=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=zc20020106

2.创建dao继承JpaRepository就好了,不用去写任何CRUD的接口的实现。

package com.haiexijun.dao;

import com.haiexijun.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface usersDao extends JpaRepository<Users,Integer> {

}

下面是一些测试代码:

import com.haiexijun.dao.usersDao;
import com.haiexijun.pojo.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class testDao {
    @Autowired
    private usersDao usersDao;

    @PersistenceContext(name = "entityManagerFactory")
    private EntityManager entityManager;

    // 测试spring data jpa的环境
    @Test
    @Transactional
    @Rollback(value = false)
    public void testInsertUser(){
        Users users=new Users();
        users.setUserName("李四");
        users.setUserAge(23);
        usersDao.save(users);
    }

    //测试usersDao注入的到底是什么
    @Test
    public void test01(){
        System.out.println(usersDao);
        //org.springframework.data.jpa.repository.support.SimpleJpaRepository@5f3b84bd
        System.out.println(usersDao.getClass());
        //class com.sun.proxy.$Proxy59
        //会发现注入的是一个代理对象

        System.out.println("======");
        JpaRepositoryFactory factory=new JpaRepositoryFactory(entityManager);
        //factory.getRepository()方法可以帮助我们为接口生成实现类,而这个实现类是SimpleJpaRepository的代理对象
        //接口必须要继承Repository接口
        usersDao ud = factory.getRepository(com.haiexijun.dao.usersDao.class);
        System.out.println(ud);
        System.out.println(ud.getClass());
    }

}

3.Repository接口详解

Repository接口是Spring Data JPA中为我们提供的所有接口中的顶层接口

repository提供了两种查询方式的支持:

(1)基于方法名称的命名规则查询

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

规则是什么?
findBy+属性名称(属性名称的首写字母要大写)+查询条件(首字母要大写)
具体更多的规则查看Spring官网即可。

userDao02:

package com.haiexijun.dao;

import com.haiexijun.pojo.Users;
import org.springframework.data.repository.Repository;

import java.util.List;


@org.springframework.stereotype.Repository
public interface userDao02 extends Repository<Users,Integer> {

     List<Users> findByUserNameIs(String name);

     List<Users> findByUserNameLike(String name);

    List<Users> findByUserNameAndUserAgeGreaterThanEqual(String name, Integer age);
}

测试用例:

    // 根据姓名查询数据
    @Test
    @Transactional
    @Rollback(value = false)
    public void test02(){
        //判断相等的条件有三种方式
        //1.什么都不写 2.is 3.equal
        List<Users> list= userDao02.findByUserNameIs("张三");
        System.out.println(list);
    }

    //根据用户姓名Like处理
    @Test
    @Transactional
    @Rollback(value = false)
    public void test03(){
        List<Users> list= this.userDao02.findByUserNameLike("张%");
        System.out.println(list);
    }

    //查询名称为王五,并且他的年龄大于等于20岁
    @Test
    @Transactional
    @Rollback(value = false)
    public void test04(){
        List<Users> list=userDao02.findByUserNameAndUserAgeGreaterThanEqual("李四",20);
        System.out.println(list);
    }

(2)基于@Query注解查询

也有如下两种方式:

通过JPQL语句查询:

JPQL是通过Hibernate的HQL演变过来的。他和HQL语法极其相似。

    //使用@Query注解
    // 可以用?index,index从1开始来传参。如:from Users where userName=?1
    //也可以用下面这种@param来传参数
    @Query(value = "from Users where userName=:name")
    List<Users> queryUsersByUserNameUseJPQL(@Param("name") String name);

    @Query(value = "from Users where userName like :name")
    List<Users> queryUsersByNameLikeUseJPQL(@Param("name") String name);

    @Query("from Users where userName=?1 and userAge>?2")
    List<Users> queryByUserNameAndUserAgeGreaterThanEqualUseJPQL(String name, int age);

@Query注解还可以通过sql语句来查询:

    // 使用@Query注解查询SQL语句
    //要开启nativeQuery为true
    @Query(value = "select * from t_users where username=? ",nativeQuery = true)
    List<Users> queryUsersByNameUseSQL(String name);

    @Query(value = "select * from t_users where username like ?",nativeQuery = true)
    List<Users> queryUsersByNameLikeUseSQL(String name);

    @Query(nativeQuery = true,value = "select * from t_users where username=? and userage>?")
    List<Users> queryByUserNameAndUserAgeGreaterThanEqualUseSQL(String name, int age);

(3)下面演示@Query注解的更新操作:
jpql编写 DAO接口update语句 还要添加@Modifying注解:

    //通过@Query注解进行数据更新
    //jpql编写 DAO接口update语句 要添加@Modifying注解
    @Query("update Users  set userAge =?2 where userId =?1 ")
    @Modifying
    void updateUserAgeById(Integer id,Integer age);

4.PagingAndSortingRepository接口

这个接口主要是帮助我们完成分页和排序处理。

(1)分页处理

我们创建一个新的Dao接口,继承至PagingAndSortingRepository接口。

我们点开这个接口的源代码查看后发现,这两个接口有2个重载的方法。这两个方法需要传入不同的参数,一个需要Sort类型的参数(用于排序),一个需要Pageable类型的参数(用于分页)。并且我们也会发现这两个方法的名称都叫做findAll(),也就是说,是对数据库表当中的所有的数据进行查询的。

package com.haiexijun.dao;

import com.haiexijun.pojo.Users;
import org.springframework.data.repository.PagingAndSortingRepository;

//继承自PagingAndSortingRepository这个接口,并且这个接口里面要传入一个泛型,泛型的一个个参数是要操作的表对应的实体类,第二个参数为表主键的数据类型
public interface UserDao01 extends PagingAndSortingRepository<Users,Integer> {
  
}

如果你比较懒,不想再创建一个人接口,也没有关系,因为我们之前用的UsersDao就是就继承自JPArepository接口,而JPArepository接口又继承了PagingAndSortingRepository这个接口,也就是说你可以用之前得Dao就可以了。

然后回到我们的测试代码当中。编写如下的测试方法来学习这个接口的相关操作。

比如说我要对数据表中所有的数据做分页处理

    /**
     * 分页
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test12(){
        //这里注意,Pageable是接口,我们不能直接new这个接口,而应该new他的接口实现类PageRequest。
        Integer page=0;// page:当前页得索引,丛林开始
        Integer size=3;// size:每页显示几条数据,这里是三条
        Pageable pageable =PageRequest.of(page,size);
        Page<Users> p= usersDao.findAll(pageable);
        System.out.println("数据得总条数:"+p.getTotalElements());
        System.out.println("数据的总页数:"+p.getTotalPages());
        List<Users> list=p.getContent();
        System.out.println("分页得结果:"+list);
    }

(2)排序处理

    /**
     * 排序
     * 对单列做排序处理
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test13(){
        // Sort对象封装了排序规则以及指定的排序字段(用对象的属性名来表示)
        //Sort构造方法可以传入两个参数
        //第一个参数direction:排序规则
        //第二个参数properties:指定做排序的属性
        Sort sort=Sort.by(Sort.Direction.DESC,"userId");
        List<Users> list=usersDao.findAll(sort);
        System.out.println(list);
    }

    /**
     * 排序
     * 对多列做排序处理
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test14(){
        // Sort对象封装了排序规则以及指定的排序字段(用对象的属性名来表示)
        //Sort构造方法可以传入两个参数
        //第一个参数direction:排序规则
        //第二个参数properties:指定做排序的属性
        //Order的构造参数与Sort的一样
        Sort.Order order1=new Sort.Order(Sort.Direction.DESC,"userAge");
        Sort.Order order2=new Sort.Order(Sort.Direction.ASC,"userId");
        Sort sort=Sort.by(order1,order2);
        List<Users> list=usersDao.findAll(sort);
        System.out.println(list);
    }

5.JpaSpecificationExecutor接口

这个接口支持多条件查询,同时支持分页与排序。

看下图,会发现JpaSpecificationExecutor接口并没有继承自任何的接口。

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

我们要新新建一个dao:

package com.haiexijun.dao;

import com.haiexijun.pojo.Users;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;


//继承自JpaSpecificationExecutor接口,这个接口传入一个泛型(要查询的表对应的实体类)。
//这个接口不能单独使用,需要配合着jpa中的其他接口一起使用
@Repository
public interface UserDao01 extends JpaSpecificationExecutor<Users>, JpaRepository<Users,Integer> {

}

(1)单条件查询:

    /**
     * 需求:根据用户姓名查询数据
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test15(){
        Specification<Users> spec=new Specification<Users>() {
            /**
             *
             * @param root :根对象。封装了查询条件的对象
             * @param query :定义了基本的查询,一般不使用
             * @param criteriaBuilder :创建一个查询的条件
             * @return Predicate:定义了查询条件
             */
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate pre= criteriaBuilder.equal(root.get("userName"),"张三");
                return pre;
            }
        };
        List<Users> list= userDao01.findAll(spec);
        System.out.println(list);
    }

(2)多条件查询

方式一:

    /**
     * 多条件查询 方式一
     *
     * 需求,要求根据用户的姓名以及年龄查询数据
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test16(){
        Specification<Users> spec=new Specification<Users>() {
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list=new ArrayList<Predicate>();
                list.add(criteriaBuilder.equal(root.get("userName"),"张三"));
                list.add(criteriaBuilder.equal(root.get("userAge"),26));
                //有几个条件就传入几个predicate对象
                Predicate[] arr=new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(arr));
            }
        };
       List<Users> list = userDao01.findAll(spec);
        System.out.println(list);
    }

方式二:

    /**
     * 多条件查询 方式二
     *
     * 需求,要求根据用户的姓名或者年龄查询数据
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test17(){
        Specification<Users> spec=new Specification<Users>() {
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.or(criteriaBuilder.equal(root.get("userName"),"张三"),criteriaBuilder.equal(root.get("userAge"),27));
            }
        };
        List<Users> list = userDao01.findAll(spec);
        System.out.println(list);
    }

多条件查询的分页查询:

    /**
     * 需求:查询姓张的用户,并做分页处理
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test18(){
        //条件
        Specification<Users> spec=new Specification<Users>() {
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

                return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
            }
        };
        //分页
        Pageable pageable=PageRequest.of(0,2);
        Page<Users> page= userDao01.findAll(spec,pageable);
        System.out.println("总条数:"+page.getTotalElements());
        System.out.println("总页数:"+page.getTotalPages());
        System.out.println(page.getContent());
    }

多条件查询的排序操作:

    /**
     * 需求:查询姓张的用户,并按用户年龄降序排序
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void  test19(){
        //条件
        Specification<Users> spec=new Specification<Users>() {
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

                return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
            }
        };
        //排序
        Sort sort=Sort.by(Sort.Direction.DESC,"userAge");
        List<Users> list=userDao01.findAll(spec,sort);
        System.out.println(list);
    }

多条件查询的分页加排序操作:

    /**
     * 需求:查询姓张的用户,做分页处理,然后按用户年龄降序排序
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void test20(){
        //排序
        Sort sort=Sort.by(Sort.Direction.DESC,"userAge");
        //分页
        Pageable pageable=PageRequest.of(0,2,sort);
        //查询条件
        Specification<Users> spec=new Specification<Users>() {
            @Override
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

                return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
            }
        };
        Page<Users> page=userDao01.findAll(spec,pageable);
        System.out.println("总条数:"+page.getTotalElements());
        System.out.println("总页数:"+page.getTotalPages());
        System.out.println(page.getContent());
    }

6.用户自定义Repository接口

我们在开发的时候,如果觉得他给的接口不足以满足需求的话,我们也可以自己去定义自己的Repository接口。

具体可以如下:

在repositoey包下面创建我们自己定义的Reposity接口,里面定义方法:

package com.haiexijun.repository;

import com.haiexijun.pojo.Users;

public interface UsersRepository {
    public Users findUserById(Integer userId);
}

然后我们定义自己的Dao类实现这个接口:

package com.haiexijun.dao;

import com.haiexijun.pojo.Users;
import com.haiexijun.repository.UsersRepository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Repository
public class UserDaoImpl implements UsersRepository {
    @PersistenceContext(name = "entityManagerFactory")
    private EntityManager em;

    @Override
    public Users findUserById(Integer userId) {
        return this.em.find(Users.class,userId);
    }
}

我们也可以定义测试方法来调用一下这个dao:

    /**
     * 测试自定义Repository
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void test21(){
        Users user= userDao.findUserById(5);
        System.out.println(user);
    }

7.关联映射的操作

(1) 一对一的关联关系

案例需求:用户与角色的一对一的联级关系

用户一方,角色一方。

案例具体的步骤如下:

分别创建两个实体类Users实体类和Roles实体类:

Users


package com.haiexijun.pojo;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "t_users")
public class Users implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增
    @Column(name = "userid")
    private Integer userId;
    @Column(name = "username")
    private String userName;
    @Column(name = "userage")
    private Integer userAge;
     //dao具体要操作那个表,就对那个表的实体类添加CascadeType
    //通过cascade = CascadeType.PERSIST来进行级联操作,使Users表在更新的同时也能更新到Roles表
    @OneToOne(cascade = CascadeType.PERSIST)
    //JoinColumn的作用就是维护一个外键
    @JoinColumn(name = "roleid")
    private Roles roles;


    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getUserAge() {
        return userAge;
    }

    public void setUserAge(Integer userAge) {
        this.userAge = userAge;
    }

    public Roles getRoles() {
        return roles;
    }

    public void setRoles(Roles roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userAge=" + userAge +
                ", roles=" + roles +
                '}';
    }
}

Roles

package com.haiexijun.pojo;

import javax.persistence.*;

@Entity
@Table(name = "t_roles")
public class Roles {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "roleid")
    private Integer roleId;
    @Column(name = "rolename")
    private String roleName;
    @OneToOne(mappedBy = "roles")
    private Users users;

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public Users getUsers() {
        return users;
    }

    public void setUsers(Users users) {
        this.users = users;
    }

    @Override
    public String toString() {
        return "Roles{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                '}';
    }
}

之后会分别在两个实体类里面添加@OneToOne注解。在通过@JoinColumn(name = “roleid”)注解在任一个实体中定义好外键。

下面编写一个测试方法来具体演示如何操作:

    /**
     * 测试一对一的关联操作
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void test22(){
        //创建角色
        Roles roles=new Roles();
        roles.setRoleName("管理员");
        //创建用户
        Users users=new Users();
        users.setUserAge(30);
        users.setUserName("毛不易");
        //建立关系
        users.setRoles(roles);
        roles.setUsers(users);
        //保存数据
        usersDao.save(users);
    }

这样,我们就完成了根据一对一关联关系来操作了数据。

下面我们在来写一个方法来测试一下通过一对一关联关系的查询操作:

    @Test
    @Transactional
    @Rollback(value = false)
    public void test23(){
        Users users=usersDao.findByUserId(7);
        System.out.println("用户信息"+users);
        Roles roles=users.getRoles();
        System.out.println(roles);
    }

(2)一对多的关联关系

上一节,通过用户和角色来学习了一对一的关联关系。这一节我们还是通过用户与角色来学习一对多的关联关系。

需求:一个用户可以对应多个角色,但是一个角色可以对应多个用户。

这是从角色到用户的一对多的关系,或者说是从用户到角色的多对一的关联关系。

角色是一方,用户是多方。

先把之前学习一对一关联关系的Roles和Users实体拿来,然后把里面的@OneToOne等一对一的相关的注解给删掉。然后重新编写一对一的关联关系的相关的注解和配置。

Roles

package com.haiexijun.pojo;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "t_roles")
public class Roles {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "roleid")
    private Integer roleId;
    @Column(name = "rolename")
    private String roleName;

    @OneToMany(mappedBy = "roles")
    private Set<Users> users=new HashSet<>();


    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public Set<Users> getUsers() {
        return users;
    }

    public void setUsers(Set<Users> users) {
        this.users = users;
    }

}

Users

package com.haiexijun.pojo;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "t_users")
public class Users implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增
    @Column(name = "userid")
    private Integer userId;
    @Column(name = "username")
    private String userName;
    @Column(name = "userage")
    private Integer userAge;

    @ManyToOne(cascade =CascadeType.PERSIST)
    @JoinColumn(name = "roleid")
    private Roles roles;


    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getUserAge() {
        return userAge;
    }

    public void setUserAge(Integer userAge) {
        this.userAge = userAge;
    }

    public Roles getRoles() {
        return roles;
    }

    public void setRoles(Roles roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userAge=" + userAge +
                ", roles=" + roles +
                '}';
    }
}

上面注意了,要把一的一方的toString()方法给去掉,负责一对多的查询操作会报错。

下面编写测试方式来学习:

    /**
     * 测试一对多的关联操作
     *
     * 添加用户,同时添加角色
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void test24(){
        //创建角色
        Roles roles=new Roles();
        roles.setRoleName("普通用户");
        //创建用户
        Users users=new Users();
        users.setUserAge(50);
        users.setUserName("黄晓明");
        //建立关系
        roles.getUsers().add(users);
        users.setRoles(roles);
        //保存数据
        usersDao.save(users);

    }

}

下面再来编写代码学习一下一对多的关联查询:

    @Test
    @Transactional
    @Rollback(value = false)
    public void test25(){
        Users users= usersDao.findByUserName("黄晓明");
        System.out.println(users);
        Roles roles=users.getRoles();
        System.out.println(roles);
    }

(3)多对多的关联操作

需求:一个角色可以拥有多个菜单,一个菜单可以分配给多个角色。

角色是多方,菜也是多方。

我们需要用到之前的Roles的实体以及新创建一个Menus实体

Roles


package com.haiexijun.pojo;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "t_roles")
public class Roles {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "roleid")
    private Integer roleId;
    @Column(name = "rolename")
    private String roleName;

    @ManyToMany
    //JoinTable的作用:
    //它可以写在任一的多对多关系的实体中,配置中间表
    //joinColumns作用:建立当前表在中间表中的外键字段
    @JoinTable(name = "t_roles_menus",joinColumns = @JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name ="menu_id"))
    private Set<Menus> menus=new HashSet<>();

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public Set<Menus> getMenus() {
        return menus;
    }

    public void setMenus(Set<Menus> menus) {
        this.menus = menus;
    }


}

Menus

package com.haiexijun.pojo;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "t_nemus")
public class Menus {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "menuid")
    private Integer menuId;
    @Column(name = "menuname")
    private String menuName;
    @Column(name = "namuurl")
    private String menuUrl;
    @Column(name = "menuid")
    private Integer fatherId;
    @ManyToMany(mappedBy ="menus" )
    private Set<Roles> roles=new HashSet<>();

    public Integer getMenuId() {
        return menuId;
    }

    public void setMenuId(Integer menuId) {
        this.menuId = menuId;
    }

    public String getMenuName() {
        return menuName;
    }

    public void setMenuName(String menuName) {
        this.menuName = menuName;
    }

    public String getMenuUrl() {
        return menuUrl;
    }

    public void setMenuUrl(String menuUrl) {
        this.menuUrl = menuUrl;
    }

    public Integer getFatherId() {
        return fatherId;
    }
  

    public void setFatherId(Integer fatherId) {
        this.fatherId = fatherId;
    }

    public Set<Roles> getRoles() {
        return roles;
    }

    public void setRoles(Set<Roles> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "Menus{" +
                "menuId=" + menuId +
                ", menuName='" + menuName + '\'' +
                ", menuUrl='" + menuUrl + '\'' +
                ", fatherId=" + fatherId +
                ", roles=" + roles +
                '}';
    }
}

下面编写测试代码来演示相关的操作:

    /**
     * 多对多关联操作
     *
     * 添加角色同时添加菜单
     */
    @Test
    @Transactional
    @Rollback(value = false)
    public void test26(){

        //创建角色对象
        Roles roles=new Roles();
        roles.setRoleName("超级管理员");
        //创建菜单对象
        //比如xxx管理平台,他下面会有用户管理等
        Menus menus1=new Menus();
        menus1.setMenuName("xxx管理平台");
        menus1.setFatherId(-1);
        menus1.setMenuUrl(null);

        Menus menus2=new Menus();
        menus2.setMenuName("用户管理");
        menus2.setFatherId(1);
        menus2.setMenuUrl(null);

        //建立关系
        roles.getMenus().add(menus1);
        roles.getMenus().add(menus2);

        menus1.getRoles().add(roles);
        menus2.getRoles().add(roles);

        //保存数据
        usersDao.save(roles);



    }

二.SpringBoot整合使用Spring Data Jpa

1.创建springboot的项目:

在这里插入图片描述

在这里插入图片描述

2.然后对项目的配置文件进行配置:

#数据库的配置
##指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=mysql
#指定jpa的自动表生成策略,驼峰自动映射为下划线格式
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.datasource.url=jdbc:mysql://localhost:3306/jpa?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=zc20020106
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#是否显示sql在控制台
spring.jpa.show-sql=true

spring.jpa.hibernate.ddl-auto

create:
每次应用启动的时候会重新根据实体建立表,之前的表和数据都会被删除。
create-drop:
和上面的功能一样,但是多了一样,就是在应用关闭的时候,也就是sessionFactory一关闭,会把表删除。
update:
最常用的,第一次启动根据实体建立表结构,之后启动会根据实体的改变更新表结构,之前的数据都在。
validate:
会验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值,运行程序会校验实体字段与数据库已有的表的字段类型是否相同,不同会报错

然后创建一个pojo包,里面创建一个实体类,具体代码如下:

package com.example.springbootjpa.pojo;

import javax.persistence.*;

//@Entity注解标注实体类,必需
@Entity
//@Table注解:对应数据库中的表, 必须, name=表名, Indexes是声明表里的索引, columnList是索引的列, 同时声明此索引列是否唯一, 默认false
@Table(name="student",indexes = {@Index(name="id",columnList = "id",unique = true),@Index(name = "name",columnList = "name",unique = true)})
public class Student {
     @Id //id用于指明主键
     //@GeneratedValue: 表明是否自动生成, 必须, strategy也是必写, 指明主键生成策略, 默认是Oracle
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     // @Column: 对应数据库列名
     @Column(name = "id")
    private Long id;
    @Column(name = "name")
    private String name;
    @Column(name = "password")
    private String password;
    @Column(name = "email")
    private String email;
    @Column(name = "age")
    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

3 然后编写一个StudentDao并继承自JpaRepository,由此我们已经继承了大部分可用的CRUD操作,针对基础操作,DAO完全不用写任何方法。

package com.example.springbootjpa.dao;

import com.example.springbootjpa.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentDao extends JpaRepository<Student,Long> {
  
}

4.接着编写一个服务接口,添加学生的保存、删除、查询全部和分页查询等的方法。

package com.example.springbootjpa.service;

import com.example.springbootjpa.pojo.Student;
import org.springframework.data.domain.Pageable;

public interface StudentService {

    //保存学生
    public void save(Student student);

    //删除学生
    public void delete(Student student);

    //查询分页数据
    public Object findPage(Pageable pageable);


}

5.继续编写服务实现类并调用DAO实现相应功能

package com.example.springbootjpa.service.impl;

import com.example.springbootjpa.dao.StudentDao;
import com.example.springbootjpa.pojo.Student;
import com.example.springbootjpa.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentDao studentDao;


    @Override
    public void save(Student student) {
        studentDao.save(student);
    }

    @Override
    public void delete(Student student) {
        studentDao.delete(student);
    }

    @Override
    public Object findPage(Integer PageNum,Integer pageSize) {
        Pageable pageable= PageRequest.of(PageNum,pageSize);
        return studentDao.findAll(pageable);
    }
}

6.接着编写一个学生控制器,调用服务接口实现对应功能。

package com.example.springbootjpa.controller;

import com.example.springbootjpa.pojo.Student;
import com.example.springbootjpa.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    private StudentService studentService;

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentService.save(student);
    }

    @PostMapping("/delete")
    public void delete(@RequestBody Student student){
        studentService.delete(student);
    }

    @GetMapping("/findAll")
    public Object findAll(){
        return studentService.findAll();
    }

    @GetMapping("/findPage")
    public Object findPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize){
        return studentService.findPage(pageNum,pageSize);
    }

}

到这里基本的整合与使用都介绍完了。如果以后我遇到其他的用法和知识点我再回来添加。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章           查看所有文章
加:2022-05-05 11:04:09  更:2022-05-05 11:09:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:14:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码