Spring与SpringBoot整合Spring Data JPA及使用

Spring与SpringBoot整合Spring Data JPA及使用,第1张

    • 一.Spring整合Spring Data JPA
      • 1.创建Spring Data JPA的项目,导入依赖,编写配置文件
      • 2.创建dao继承JpaRepository就好了,不用去写任何CRUD的接口的实现。
      • 3.Repository接口详解
      • 4.PagingAndSortingRepository接口
      • 5.JpaSpecificationExecutor接口
      • 6.用户自定义Repository接口
      • 7.关联映射的 *** 作
    • 二.SpringBoot整合使用Spring Data Jpa
      • 1.创建springboot的项目:
      • 2.然后对项目的配置文件进行配置:
      • 3 然后编写一个StudentDao并继承自JpaRepository,由此我们已经继承了大部分可用的CRUD *** 作,针对基础 *** 作,DAO完全不用写任何方法。
      • 4.接着编写一个服务接口,添加学生的保存、删除、查询全部和分页查询等的方法。
      • 5.继续编写服务实现类并调用DAO实现相应功能
      • 6.接着编写一个学生控制器,调用服务接口实现对应功能。

本节由浅入深,再浅出学习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>
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-beansartifactId>
        <version>5.3.18version>
    dependency>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-contextartifactId>
        <version>5.3.18version>
    dependency>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-coreartifactId>
        <version>5.3.18version>
    dependency>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-expressionartifactId>
        <version>5.3.18version>
    dependency>

    
    <dependency>
        <groupId>org.aspectjgroupId>
        <artifactId>aspectjweaverartifactId>
        <version>1.9.8.RC2version>
    dependency>

    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-aopartifactId>
        <version>5.3.18version>
    dependency>

    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-jdbcartifactId>
        <version>5.3.18version>
    dependency>

    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-txartifactId>
        <version>5.3.18version>
    dependency>

    
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-ormartifactId>
        <version>5.3.18version>
    dependency>

    
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.13version>
        <scope>testscope>
    dependency>

    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-testartifactId>
        <version>5.3.18version>
    dependency>

    
    
    <dependency>
        <groupId>commons-logginggroupId>
        <artifactId>commons-loggingartifactId>
        <version>1.2version>
    dependency>

    
    
    <dependency>
        <groupId>antlrgroupId>
        <artifactId>antlrartifactId>
        <version>2.7.7version>
    dependency>

    
    <dependency>
        <groupId>org.dom4jgroupId>
        <artifactId>dom4jartifactId>
        <version>2.1.3version>
    dependency>

    
    <dependency>
        <groupId>org.apache.geronimo.specsgroupId>
        <artifactId>geronimo-jta_1.1_specartifactId>
        <version>1.1.1version>
    dependency>

    
    <dependency>
        <groupId>org.hibernate.commongroupId>
        <artifactId>hibernate-commons-annotationsartifactId>
        <version>5.1.2.Finalversion>
    dependency>

    
    <dependency>
        <groupId>org.hibernategroupId>
        <artifactId>hibernate-coreartifactId>
        <version>5.6.5.Finalversion>
    dependency>

    
    <dependency>
        <groupId>org.hibernate.javax.persistencegroupId>
        <artifactId>hibernate-jpa-2.1-apiartifactId>
        <version>1.0.0.Finalversion>
    dependency>

    
    <dependency>
        <groupId>org.jbossgroupId>
        <artifactId>jandexartifactId>
        <version>2.0.0.Finalversion>
    dependency>

    
    <dependency>
        <groupId>org.javassistgroupId>
        <artifactId>javassistartifactId>
        <version>3.28.0-GAversion>
    dependency>

    
    <dependency>
        <groupId>org.jboss.logginggroupId>
        <artifactId>jboss-loggingartifactId>
        <version>3.4.1.Finalversion>
    dependency>

    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>8.0.25version>
    dependency>

    
    <dependency>
        <groupId>com.mchangegroupId>
        <artifactId>c3p0artifactId>
        <version>0.9.5.5version>
    dependency>

    
    <dependency>
        <groupId>org.hibernategroupId>
        <artifactId>hibernate-c3p0artifactId>
        <version>5.6.7.Finalversion>
    dependency>

    <dependency>
        <groupId>com.mchangegroupId>
        <artifactId>mchange-commons-javaartifactId>
        <version>0.2.19version>
    dependency>

    
    <dependency>
        <groupId>org.hibernategroupId>
        <artifactId>hibernate-entitymanagerartifactId>
        <version>5.6.7.Finalversion>
    dependency>

    

    
    <dependency>
        <groupId>org.springframework.datagroupId>
        <artifactId>spring-data-commonsartifactId>
        <version>2.6.3version>
    dependency>

    
    <dependency>
        <groupId>org.springframework.datagroupId>
        <artifactId>spring-data-jpaartifactId>
        <version>2.6.3version>
    dependency>

    
    <dependency>
        <groupId>log4jgroupId>
        <artifactId>log4jartifactId>
        <version>1.2.17version>
    dependency>

    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-apiartifactId>
        <version>1.7.36version>
    dependency>

    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-log4j12artifactId>
        <version>1.7.28version>
    dependency>

dependencies>

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


<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">

    
    <context:property-placeholder location="classpath:jdbc.properties"/>

    
    <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>

    
    <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">
                
                
                <property name="database" value="MYSQL"/>
                
                <property name="generateDdl" value="true"/>
                
                <property name="showSql" value="true"/>
            bean>
        property>
        
        <property name="packagesToScan">
            <list>
                <value>com.haiexijun.pojovalue>
            list>
        property>
    bean>

    
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    bean>


    
    <tx:annotation-driven transaction-manager="transactionManager"/>

    
    <context:component-scan base-package="com.haiexijun"/>

    
    
    <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)基于方法名称的命名规则查询

规则是什么?
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接口并没有继承自任何的接口。

我们要新新建一个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 spec=new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {

                return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
            }
        };
        //排序
        Sort sort=Sort.by(Sort.Direction.DESC,"userAge");
        List 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);
    }

}

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/801539.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-07
下一篇 2022-05-07

发表评论

登录后才能评论

评论列表(0条)

保存