zoukankan      html  css  js  c++  java
  • SpringDataJPA使用

    一、简介

      SpringDataJpa是 JPA规范的一个很好的实现,简化了开发的复杂度,极大提升了开发的效率。SpringDataJpa通过 Repository接口及子接口可以很方便的实现持久化操作。

      SpringDataJpa的API在线手册:https://docs.spring.io/spring-data/jpa/docs/2.1.0.RELEASE/api/

      简单的看下 Repository 类层次结构图关系:

      

       Repository:空的父接口,即是一个标记接口。

       CrudRepository:Repository的子接口,提供CRUD操作

       PagingAndSortingRepository:CrudRepository的子接口,增加 分页 和 排序的功能

      JpaRepository:PagingAndSortingRepository、QueryByExampleExecutor的子接口,增加 批量操作 以及 QBE查询

      SimpleJpaRepository:实现了JpaRepository 和 JpaSpecificationExecutor 接口,构造函数中传入 EntityManager。类上注解了@Transactional(readOnly = true),对于CUD的方法使用了注解@Transactional,局部有限原则。各种方法最终的实现都依托于 EntityManager来完成。

    二、使用

      1、创建springboot项目 springdata-jpa

      2、src/main/resources 目录下新建 application.properties,内容如下:

    db.driverClass=com.mysql.jdbc.Driver
    db.jdbcUrl=jdbc:mysql://localhost:3310/boot?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    db.username=root
    db.password=123456
    spring.jpa.properties.hibernate.show_sql=true
    spring.jpa.properties.hibernate.format_sql=true
    #修改实体类的匹配命名规则,主要影响@column(name="")配置,默认是驼峰匹配法
    spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

      3、创建 DataSource configuration:

    package com.cfang.confingurations;
    
    import javax.sql.DataSource;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    @Configuration
    public class DataSourceConfigurations {
    
        @Value("${db.driverClass:com.mysql.jdbc.Driver}")
        private String driverClass;
        @Value("${db.jdbcUrl}")
        private String jdbcUrl;
        @Value("${db.username}")
        private String username;
        @Value("${db.password}")
        private String password;
        @Value("${initialSize:10}")
        private Integer initialSize;    //初始化连接池个数
        @Value("${maxActive:20}")
        private Integer maxActive;    //最大连接数 
        @Value("${maxWait:60000}")
        private Long maxWait;    //获取连接等待超时时间,单位毫秒
        @Value("${timeBetweenEvictionRunsMillis:60000}")
        private Long timeBetweenEvictionRunsMillis;    //间隔多久进行一次检测,检测回收需要关闭的空闲链接,单位毫秒
        @Value("${minEvictableIdleTimeMillis:300000}")
        private Long minEvictableIdleTimeMillis;    //定义一个连接在池中的最小生存时间,单位毫秒
        @Value("${validationQuery:select 1 from dual}")
        private String validationQuery;    //用来检测连接是否有效的sql
        @Value("${testWhileIdle:true}")
        private Boolean testWhileIdle;    //申请连接的时候是否检测。如果空间时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效
        @Value("${testOnBorrow:false}")
        private Boolean testOnBorrow;    
        @Value("${testOnReturn:false}")
        private Boolean testOnReturn;    //归还连接的时候,是否validationQuery检查连接的有效性,true执行的话,降低性能
        @Value("${poolPreparedStatements:false}")
        private Boolean poolPreparedStatements;    //是否打开pscache
        @Value("${maxPoolPreparedStatementPerConnectionSize:20}")
        private int maxPoolPreparedStatementPerConnectionSize;    //指定每个连接的pscache的大小
        
        @Bean
        public DataSource initDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driverClass);
            dataSource.setUrl(jdbcUrl);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            dataSource.setInitialSize(initialSize);
            dataSource.setMaxActive(maxActive);
            dataSource.setMaxWait(maxWait);
            dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            dataSource.setValidationQuery(validationQuery);
            dataSource.setTestWhileIdle(testWhileIdle);
            dataSource.setTestOnBorrow(testOnBorrow);
            dataSource.setTestOnReturn(testOnReturn);
            dataSource.setPoolPreparedStatements(poolPreparedStatements);
            if(poolPreparedStatements) {
                dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
            }
            return dataSource;
        }
    }

      4、创建User实体

    package com.cfang.entity;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    import lombok.Data;
    
    @Entity
    @Table(name = "tb_user")
    @Data
    public class TblUserEntity {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private int id;
        @Column(name = "name")
        private String name;
        @Column(name = "password")
        private String password;
        @Column(name = "age")
        private int age;
    }

      5、创建持久化操作Repository:

    package com.cfang.repository;
    
    import java.util.List;
    
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.data.jpa.repository.Modifying;
    import org.springframework.data.jpa.repository.Query;
    import org.springframework.data.repository.query.Param;
    
    import com.cfang.entity.TblUserEntity;
    
    public interface UserRepository extends JpaRepository<TblUserEntity, Integer>, JpaSpecificationExecutor<TblUserEntity>{
    
        /**
         *     springdata关键字命名方法,可不写实现
         */
        TblUserEntity findByName(String name);
        TblUserEntity findByNameAndAge(String name, int age);
        List<TblUserEntity> findByNameLikeAndAge(String name, int age);
        
        Page<TblUserEntity> findUserPageByNameLike(String name, Pageable pageable);
        
        /**
         * JPQL
         */
        @Query(value = "from TblUserEntity where id=?1", nativeQuery = false)
        TblUserEntity readIdByJPQL(int id);
        
        @Query(value = "select * from tb_user where id=:id", nativeQuery = true)
        TblUserEntity readIdBySQL(int id);
        
        @Modifying
        @Query(value = "update TblUserEntity set name=?2 where id=?1", nativeQuery = false)
        int updateUserNameByIdJPQL(int id, String name);
        
        @Modifying
        @Query(value = "update tb_user set name=:name where id=:id", nativeQuery = true)
        int updateUserNameByIdSQL(@Param("id")int id, @Param("name")String name);
        
        @Query(value = "from TblUserEntity where name like %?1%", nativeQuery = false)
        List<TblUserEntity> findUserByNameJPQL(String name);
        
        @Query(value = "select * from tb_user where name like %:name%", nativeQuery = true)
        List<TblUserEntity> findUserByNameSQL(String name);
        
    }

      6、创建 junit 测试

    package com.cfang.repository;
    
    import java.util.List;
    
    import javax.persistence.criteria.CriteriaBuilder;
    import javax.persistence.criteria.CriteriaQuery;
    import javax.persistence.criteria.Predicate;
    import javax.persistence.criteria.Root;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.jpa.domain.Specification;
    import org.springframework.test.annotation.Rollback;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.web.WebAppConfiguration;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.alibaba.fastjson.JSON;
    import com.cfang.SpringDataJpaApplication;
    import com.cfang.entity.TblUserEntity;
    import com.google.common.collect.Lists;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = {SpringDataJpaApplication.class})
    @WebAppConfiguration
    public class UserTest {
    
        @Autowired
        private UserRepository userRepository;
        
        @Test
        public void findByName() {
            TblUserEntity entity = userRepository.findByName("lisi");
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void findByNameAndAge() {
            TblUserEntity entity = userRepository.findByNameAndAge("lisi", 22);
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void findByNameLikeAndAge() {
            List<TblUserEntity> entity = userRepository.findByNameLikeAndAge("li%", 22);
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void readIdByJPQL() {
            TblUserEntity entity = userRepository.readIdByJPQL(27);
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void readIdBySQL() {
            TblUserEntity entity = userRepository.readIdBySQL(27);
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        @Transactional
        @Rollback(false)
        public void updateUserNameByIdJPQL() {
            int result = userRepository.updateUserNameByIdJPQL(27, "wangwu");
            log.info("result:{}", result);
        }
        
        @Test
        @Transactional
        @Rollback(false)
        public void updateUserNameByIdSQL() {
            int result = userRepository.updateUserNameByIdSQL(27, "wangwu2");
            log.info("result:{}", result);
        }
        
        @Test
        public void findUserByNameJPQL() {
            List<TblUserEntity> entity = userRepository.findUserByNameJPQL("li");
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void findUserByNameSQL() {
            List<TblUserEntity> entity = userRepository.findUserByNameSQL("li");
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void findUserPageByNameLike() {
            Pageable pageable = PageRequest.of(0, 2, new Sort(Sort.Direction.DESC, "id"));
            Page<TblUserEntity> entity = userRepository.findUserPageByNameLike("li%", pageable);
            log.info("result:{}", JSON.toJSONString(entity));
        }
        
        @Test
        public void testSpecification() {
            Pageable pageable = PageRequest.of(0, 2, Sort.Direction.DESC, "id");
            String name = "li";
            Specification<TblUserEntity> specification = new Specification<TblUserEntity>() {
                @Override
                public Predicate toPredicate(Root<TblUserEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                    List<Predicate> conditions = Lists.newArrayList();
                    Predicate condition = null;
                    condition = criteriaBuilder.like(root.get("name"), "%" + name + "%");
                    conditions.add(condition);
                    condition = criteriaBuilder.greaterThan(root.get("id"), 27);
                    conditions.add(condition);
                    
                    Predicate[] arr = new Predicate[conditions.size()];
    //                return criteriaBuilder.and(conditions.toArray(arr));
                    query.where(conditions.toArray(arr));
                    return null;
                }
            };
            Page<TblUserEntity> result = userRepository.findAll(specification, pageable);
            log.info("result:{}", JSON.toJSONString(result));
        }
        
    }

      ps:在进行 repository 的CUD操作的时候,必须加事务支持 @Transactional,否则会报错(截取部分出错信息):

    org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
    Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query

    三、总结

      数据进行持久化操作的时候,都是需要一个对象来进行相关操作的,原生的Hibernate中使用Session,JPA中使用EntityManager,MyBatis中使用SqlSession。上述工程中,在主类main方法中可添加如下进行查看:

    @Bean
        public Object testTransactionManager(PlatformTransactionManager manager) {
            System.out.println("TransactionManager is : " + manager.getClass().getName());
            return new Object();
        }

      SpringDataJpa提供了丰富的CRUD构造的方法,具体可根据实际情况查询使用。

  • 相关阅读:
    Linux下安装nginx
    MySQL基础
    win10 安装MySQL 5.7.27
    Java IO之File
    java并发编程之ThreadLocal
    原生JS 的60秒倒计时!
    vueX 配合路由导航配置动态路由
    JS获取 当前时间是本年的第几天? 第几周?
    vue书写echarts 100px大小问题
    VUE 父组件与子组件双向数据绑定的方法 做弹框绑定列表页数据的举例
  • 原文地址:https://www.cnblogs.com/eric-fang/p/11692645.html
Copyright © 2011-2022 走看看