zoukankan      html  css  js  c++  java
  • Spring Boot 入门之持久层篇(三)

    博客地址:http://www.moonxy.com

    一、前言

    当前数据库的持久层框架主要分为两种架构模式,即以 SQL 为中心和以对象为中心。

    Spring JDBC Template 和 MyBatis 等数据库持久层框架,都是以 SQL 为核心,而 Spring Data 和 Hibernate 等,则是以对象为核心的持久层框架。Spring Data JPA 是 Spring Data 的一个子项目,主要用于简化数据访问层的实现,使用 Spring Data JPA 可以轻松实现增删改查、分页和排序等。

    二、整合 Spring JDBC Template

    2.1 配置数据源

    这里使用坊间流传的最快的数据库连接池 HikariCP 来整合 Spring JDBC Template,集成到 Spring Boot,添加 pom 依赖:

    <!-- HikariCP -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>2.7.2</version>
    </dependency>

    然后在配置文件中配置连接数据库的基本信息以供 HikariCP 使用:

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=123456

    配置 MySQL 的驱动依赖:

    <!-- MySQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>6.0.5</version>
    </dependency>

    配置好上述依赖包和配置文件后,还需要编写一个 Java Config 来创建一个数据源,如下:

    package com.light.springboot.conf;
    
    
    import javax.sql.DataSource;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.env.Environment;
    
    import com.zaxxer.hikari.HikariDataSource;
    
    @Configuration
    public class DataSourceConfig {
        
        @Bean(name="dataSource")
        public DataSource datasource(Environment env) {
            HikariDataSource ds = new HikariDataSource();
            ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
            ds.setJdbcUrl(env.getProperty("spring.datasource.url"));
            ds.setUsername(env.getProperty("spring.datasource.username"));
            ds.setPassword(env.getProperty("spring.datasource.password"));
            return ds;
        }
    }

    2.2 建表

    此处使用 MySQL 数据库,创建两张表结构:

    --用户表
    create table user(
    id int(11) not null auto_increment,
    name varchar(45) collate utf8_bin default null comment '名称',
    department_id int(11) default null,
    create_time date default null comment '创建时间',
    primary key (id)
    )ENGINE=innoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    
    --部门表
    create table department(
    id int(11) not null auto_increment,
    name varchar(45) collate utf8_bin default null,
    primary key (id)
    )ENGINE=innoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    
    --测试数据
    insert into department(name) values("Development");
    insert into department(name) values("Test");
    insert into department(name) values("Production");

    2.3 建立实体类

    建议实体类实现序列化接口,如下:

    package com.light.springboot.entity;
    
    import java.io.Serializable;
    import java.util.Date;
    
    import com.fasterxml.jackson.annotation.JsonFormat;
    
    public class User implements Serializable {
        
        private static final long serialVersionUID = 8886402739972726962L;
        
        private int id;
        private String name;
        private int departmentId;
        
        @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", locale = "zh" , timezone="GMT+8")
        private Date createDate;
    
        @Override
        public String toString() {
            return "UserEntity [id=" + id + ", name=" + name + ", departmentId=" + departmentId + ", createDate=" + createDate + "]";
        }
    
        // 省略 Setter 和 Getter 方法
    }

    2.4 建立接口和实现类

    接口提供常用的 CRUD 方法定义,如下:

    package com.light.springboot.dao;
    
    import java.util.List;
    
    import com.light.springboot.entity.User;
    
    public interface UserDao {
        
        public Integer insertUser(User user);
        
        public Integer deleteUserById(Integer id);
        
        public Integer updateUserById(User user);
        
        public User getUserById(Integer id);
        
        public List<User> getUserByDepartmentId(Integer id);
        
        public Integer getUserCountByDepartmentId(Integer departmentId);
        
        public Integer newUpdateUserById(User user);
    }

    Spring 提供了 JdbcTemplate 对数据库访问技术 JDBC 做了一定封装,包括管理数据库连接,简单查询结果映射成 Java 对象,复杂的结果集通过实现 RowMapper 接口来映射到 Java 对象。在 Spring Boot 中,只要配置好数据源 DataSource,就能自动使用 JdbcTemplate(org.springframework.jdbc.core.JdbcTemplate),查看 JdbcTemplate 源码后,发现其提供了 dataSource 的 Set 注入方法: setDataSource(dataSource);所以 Spring 容器中只要存在 dataSource 的 bean,便会自动装配 JdbcTemplate 类。

    实现类提供了上面接口的 CRUD 方法的实现过程,@Repository 注解通过作用在和存储相关的实现类上,如下:

    package com.light.springboot.dao.impl;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.PreparedStatementCreator;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
    import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
    import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
    import org.springframework.jdbc.core.namedparam.SqlParameterSource;
    import org.springframework.jdbc.support.GeneratedKeyHolder;
    import org.springframework.jdbc.support.KeyHolder;
    import org.springframework.stereotype.Repository;
    
    import com.light.springboot.dao.UserDao;
    import com.light.springboot.entity.User;
    
    @Repository
    public class UserDaoImpl implements UserDao {
        
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        @Autowired
        private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
        
        /**
         * JdbcTemplate提供的update方法,可以用于新增、修改、删除、执行存储过程等
         * 如果是数据库插入,对于MySQL、SQL Server等数据库,含有自增序列时,则需要提供一个KeyHolder来存放返回的序列
         */
        @Override
        public Integer insertUser(User user) {
            String sql = "insert into user(name, department_id, create_time) values(?,?,?)";
            KeyHolder keyHolder = new GeneratedKeyHolder();
            jdbcTemplate.update(new PreparedStatementCreator() {
                public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                    // 指出自增主键的列名
                    PreparedStatement ps = connection.prepareStatement(sql, new String[] {"id"});
                    ps.setString(1, user.getName());
                    ps.setInt(2, user.getDepartmentId());
                    ps.setDate(3, new java.sql.Date(new java.util.Date().getTime()));
                    return ps;
                }
            }, keyHolder);
            return keyHolder.getKey().intValue();
        }
    
        @Override
        public Integer deleteUserById(Integer id) {
            String sql = "delete from user where id = ?";
            return this.jdbcTemplate.update(sql,id);
        }
    
        @Override
        public Integer updateUserById(User user) {
            String sql = "update user set name = ?, department_id=? where id = ?";
            return jdbcTemplate.update(
                    sql, 
                    user.getName(),
                    user.getDepartmentId(),
                    user.getId()
                    );
        }
        
        /**
         * JdbcTemplate需要一个RowMapper,将查询结果集ResultSet映射成一个对象
         */
        @Override
        public User getUserById(Integer id) {
            String sql = "select * from user where id = ?";
            return jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
                @Override
                public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                    User user = new User();
                    user.setId(rs.getInt("id"));
                    user.setName(rs.getString("name"));
                    user.setDepartmentId(rs.getInt("department_id"));
                    user.setCreateDate(rs.getDate("create_time"));
                    return user;
                }
                
            },id);
        }
        
        /**
         * 也可以创建一个内部类UserRowMapper作为查询复用
         * @author Administrator
         *
         */
        static class UserRowMapper implements RowMapper<User>{
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setDepartmentId(rs.getInt("department_id"));
                user.setCreateDate(rs.getDate("create_time"));
                return user;
            }
        }
        
        /**
         * 如果返回的结果为列表,则需要使用query方法
         */
        @Override
        public List<User> getUserByDepartmentId(Integer departmentId) {
            String sql = "select * from user where department_id = ?";
            List<User> userList = jdbcTemplate.query(sql, new UserRowMapper(), departmentId);
            return userList;
        }
    
        /**
         * MapSqlParameterSource是一个类似Map风格的类,包括 Key-Value,Key就是SQL中的参数
         */
        @Override
        public Integer getUserCountByDepartmentId(Integer departmentId) {
            String sql = "select count(1) from user where department_id = :deptId";
            MapSqlParameterSource namedParameters = new MapSqlParameterSource();
            namedParameters.addValue("deptId", departmentId);
            Integer count = namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
            return count;
        }
        
        /**
         * 使用SqlParameterSource来封装任意的JavaBean
         */
        @Override
        public Integer newUpdateUserById(User user) {
            String sql = "update user set name = :name, department_id = :departmentId where id = :id";
            SqlParameterSource source = new BeanPropertySqlParameterSource(user);
            return namedParameterJdbcTemplate.update(sql, source);
        }
        
    }

    2.5 Spring Boot 单元测试

    Spring Boot 单元测试需要添加如下依赖:

    <!-- Spring Boot 单元测试 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>        

    在 test/java 目录添加单元测试代码,如下:

    import java.util.Date;
    import java.util.List;
    
    import org.junit.Ignore;
    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.test.context.junit4.SpringRunner;
    
    import com.light.springboot.SpringbootApplication;
    import com.light.springboot.dao.UserDao;
    import com.light.springboot.entity.User;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes=SpringbootApplication.class)
    public class UserDaoTest {
    
        @Autowired
        private UserDao userDao;
    
        /**
         * 新增用户
         */
        @Test
        @Ignore
        public void testInsertUser() {
            User user = new User();
            user.setName("Bob");
            user.setDepartmentId(2);
            user.setCreateDate(new Date());
            
            int result = this.userDao.insertUser(user);
            System.out.println(result);
        }
        
        /**
         * 通过id查找单个用户
         */
        @Test
        @Ignore
        public void testGetUserById() {
            User user = this.userDao.getUserById(1);
            System.out.println(user.getName());
        }
        
        /**
         * 通过id修改单个用户
         */
        @Test
        @Ignore
        public void testUpdateUserById() {
            User user = new User();
            user.setId(1);
            user.setName("Deft");
            user.setDepartmentId(2);
            this.userDao.updateUserById(user);
        }
        
        /**
         * 通过id删除单个用户
         */
        @Test
        @Ignore
        public void testDeleteUserById() {
            int result = this.userDao.deleteUserById(1);
            System.out.println(result);
        }
        
        /**
         * 通过部门id查找多个用户
         */
        @Test
        @Ignore
        public void testGetUserByDepartmentId() {
            List<User> userList = this.userDao.getUserByDepartmentId(1);
            System.out.println(userList.size());
        }
        
        /**
         * 使用MapSqlParameterSource
         */
        @Test
        @Ignore
        public void testGetUserCountByDepartmentId() {
            Integer userCount = this.userDao.getUserCountByDepartmentId(1);
            System.out.println(userCount);
        }
        
        /**
         * 使用MapSqlParameterSource
         */
        @Test
        @Ignore
        public void testNewUpdateUserById() {
            User user = new User();
            user.setId(1);
            user.setName("Rain");
            user.setDepartmentId(2);
            Integer count = this.userDao.newUpdateUserById(user);
            System.out.println(count);
        }
    }

    其中,@RunWith 是 JUnit 标准的一个注解,用来告诉 JUnit 单元测试框架不要使用内置的方式进行单元测试,而应使用 RunWith 指明的类来提供单元测试,所有的 Spring 单元测试总是使用 SpringRunner.class。

    @SpringBootTest 用于 Spring Boot 应用测试,它默认会根据包名逐级网上找,当测试类和主程序在同一个包下时,可以不用配置 classes,Spring 会一直找到 Spring Boot 主程序,也就是通过类注解是否包含@SpringBootApplication 来判断是否是主程序,并在单元测试的时候启动该类来创建 Spring 上下文环境。但当测试类和主程序不在同一个包下时,需要添加 classes,指定主程序启动类,如 classes=SpringbootApplication.class。

    @Ignore 表示在测试时要跳过的方法,测试时可以单个测试。

    2.6 JdbcTemplate 增强

    NamedParameterJdbcTemplate 继承了 JdbcTemplate,JdbcTemplate 对 SQL 中的参数只支持传统的 "?" 占位符。NamedParameterJdbcTemplate 允许 SQL 中使用参数的名字作为占位符。

    MapSqlParameterSource是一个类似Map风格的类,包括 Key-Value,Key就是SQL中的参数,如上面的:getUserCountByDepartmentId 方法;

    Spring 还提供了 SqlParameterSource 类来封装任意的 JavaBean,为 NamedParameterJdbcTemplate 提供参数,JavaBean 的属性名称作为 SQL 的参数名字,如上面的:newUpdateUserById 方法。

    三、整合 Spring Data JPA

    Spring Data JPA 采用了 Hibernate 实现,以对象为中心,属于 ORM(Object Relational Mapping)工具,对实体和实体关系的操作会映射到数据库操作。

    3.1 添加依赖

    添加 Spring Data JPA、HikariCP 数据源连接池和 MySQL 数据库驱动依赖,如下:

    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- HikariCP -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>2.7.2</version>
    </dependency>
    
    <!-- MySQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>6.0.5</version>
    </dependency>

    3.2 数据库连接配置和 JPA 配置

    # 数据库连接配置
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=123456
    
    # JPA 配置
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true

    spring.jpa.hibernate.ddl-auto,是否自动建库,默认为 none。有如下取值可以选择:

    create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因;

    create-drop:每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除;

    update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会;

    validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值;

    也可将其设置为 none,表示框架不执行任何操作。

    spring.jpa.show-sql,是否自动打印 SQL,默认为 false。

    配置好上述依赖包和配置文件后,还需要编写一个 Java Config 来创建一个数据源,如下:

    package com.light.springboot.conf;
    
    
    import javax.sql.DataSource;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.env.Environment;
    
    import com.zaxxer.hikari.HikariDataSource;
    
    @Configuration
    public class DataSourceConfig {
        
        @Bean(name="dataSource")
        public DataSource datasource(Environment env) {
            HikariDataSource ds = new HikariDataSource();
            ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
            ds.setJdbcUrl(env.getProperty("spring.datasource.url"));
            ds.setUsername(env.getProperty("spring.datasource.username"));
            ds.setPassword(env.getProperty("spring.datasource.password"));
            return ds;
        }
    }

    3.3 建立实体类

    现在越来越多的 JPA 应用采用简化的 Entity 定义,去掉了关系映射的相关配置,去掉了数据库外键设置。一个表对应一个简单的实体,这样弱关联使用 JPA 更加容易。

    package com.light.springboot.entity;
    
    import java.io.Serializable;
    import java.util.Date;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    
    import com.fasterxml.jackson.annotation.JsonFormat;
    
    @Entity
    public class User implements Serializable {
        
        private static final long serialVersionUID = 8886402739972726962L;
        
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        private int id;
        
        @Column
        private String name;
        
        @Column(name="department_id")
        private int departmentId;
        
        @Column(name="create_time")
        @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", locale = "zh" , timezone="GMT+8")
        private Date createDate;
        
        @Override
        public String toString() {
            return "UserEntity [id=" + id + ", name=" + name + ", departmentId=" + departmentId + ", createDate=" + createDate + "]";
        }
    
        // 省略 Setter 和 Getter 方法
    }

    其中,@Entity 注解指名这是一个实体 Bean,@Table 注解指定了 Entity 所要映射的数据库表,其中@Table.name()用来指定映射表的表名。如果缺省 @Table 注解,系统默认采用类名作为映射表的表名。实体 Bean 的每个实例代表数据表中的一行数据,行中的一列对应实例中的一个属性。

    3.4 建立接口

    Spring Data 提供如下接口供开发者使用:

    Repository:仅仅是一个标识,表明任何继承它的均为仓库接口类,方便 Spring 自动扫描识别;

    CrudRepository:继承Repository,实现了一组 CRUD 相关的方法;

    PagingAndSortingRepository:继承 CrudRepository,实现了一组分页排序相关的方法;

    JpaRepository:继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法;

    JpaSpecificationExecutor:比较特殊,不属于Repository体系,实现一组 JPA Criteria 查询相关的方法;

    即 JpaRepository 继承 PagingAndSortingRepository 继承 CrudRepository 继承 Repository。

    我们自己定义的 XxxxRepository 需要继承 JpaRepository,这样我们的 XxxxRepository 接口就具备了通用的数据访问控制层的能力。

    package com.light.springboot.dao;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import com.light.springboot.entity.User;
    
    public interface UserRepository extends JpaRepository<User, Integer> {
    
    }

    接口中不需要任何方法的声明,查看 JpaRepository 源码,发现已经提供好了常用的基本方法,已经具备了实现存取数据库的功能了,可以对数据库进行增删改查、进行分页查询和指定排序的字段等操作了。

    3.5 基于方法名字查询

    Spring 还提供了通过查询的方法名和参数名来自动构造一个 JPA OQL(JPA 对象查询语言)查询,可以在如上的 UserRepository 中添加几个查询方法,如:

    package com.light.springboot.dao;
    
    import java.sql.Date;
    import java.util.List;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import com.light.springboot.entity.User;
    
    public interface UserRepository extends JpaRepository<User, Integer> {
        
        public List<User> findByName(String name);
        
        public List<User> queryByIdOrName(String id, String name);
        
        public List<User> queryByCreateDateGreaterThanEqual(Date start);
    }

    方法名和参数名需要遵守一定的规则,Spring Data JPA 才能自动转化为 JPQL。方法名可以使用 findBy、getBy、queryBy 和 readBy 开头,作为方法名的前缀,拼接实体类中的属性字段(首个字母大写),并可选拼接一些 SQL 查询关键字来组合成一个查询方法。

    3.6 使用 @Query 注解

    也可以在上面的的 UserRepository 接口方法中添加 @Query 注解来使用 JPQL,如下:

    @Query("select u from User u where u.name=?1 and u.departmentId=?2")
    public User findUser(String name, Integer departmentId);
    
    @Query(value="select * from user where name=?1 and department_id=?2", nativeQuery=true)
    public User findUserByNativeQuery(String name, Integer departmentId);

    3.7 创建单元测试类

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    
    import org.junit.Ignore;
    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.Sort;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import com.light.springboot.SpringbootApplication;
    import com.light.springboot.dao.UserRepository;
    import com.light.springboot.entity.User;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes=SpringbootApplication.class)
    public class UserRepositoryTest {
    
        @Autowired
        private UserRepository userRepository;
    
        /**
         * 新增用户
         */
        @Test
        @Ignore
        public void testInsertUser() {
            User user = new User();
            user.setName("Jim");
            user.setDepartmentId(2);
            user.setCreateDate(new Date());
            
            User resultUser = this.userRepository.save(user);
            System.out.println(resultUser.toString());
        }
        
        /**
         * 通过id查找单个用户
         */
        @Test
        @Ignore
        public void testGetUserById() {
            User user = this.userRepository.findOne(2);
            System.out.println(user.toString());
        }
        
        /**
         * 通过id修改单个用户
         */
        @Test
        @Ignore
        public void testUpdateUserById() {
            User user = this.userRepository.findOne(2);
            user.setId(2);
            user.setName("Deft");
            user.setDepartmentId(2);
            this.userRepository.save(user);
        }
        
        /**
         * 通过id删除单个用户
         */
        @Test
        @Ignore
        public void testDeleteUserById() {
            this.userRepository.delete(2);
        }
        
        /**
         * 查找所有的用户
         */
        @Test
        @Ignore
        public void testGetAllUser() {
            Sort sort = new Sort(Sort.Direction.DESC, "id");//默认升序,可以指定为按照id降序
            List<User> userList = this.userRepository.findAll(sort);
            System.out.println(userList.size());
        }
        
        /**
         * 自定义方法:通过name查询
         */
        @Test
        @Ignore
        public void testFindByName() {
            List<User> userList = this.userRepository.findByName("Adam");
            System.out.println(userList.size());
        }
        
        /**
         * 自定义方法:通过id或name查询
         */
        @Test
        @Ignore
        public void testQueryByIdOrName() {
            List<User> userList = this.userRepository.queryByIdOrName(3, "Adam");
            System.out.println(userList.size());
        }
        
        /**
         * 自定义方法:大于等于某个创建日期的用户
         * @throws ParseException 
         */
        @Test
        @Ignore
        public void testQueryByCreateDateGreaterThanEqual() throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse("2018-02-03");
            List<User> userList = this.userRepository.queryByCreateDateGreaterThanEqual(date);
            System.out.println(userList.size());
        }
        
        /**
         * 使用@Query注解实现自定义JPA SQL
         */
        @Test
        @Ignore
        public void testFindUser() {
            User user = this.userRepository.findUser("Adam", 1);
            System.out.println(user.toString());
        }
        
        /**
         * 使用@Query注解实现自定义原生SQL
         */
        @Test
    @Ignore
    public void testFindUserByNativeQuery() { User user = this.userRepository.findUser("Bob", 2); System.out.println(user.toString()); } }

    四、常见数据库连接池对比

    在日常开发中,常见的开源数据库连接池有:Hikari、Druid、C3p0、Dbcp 和 Tomcat-jdbc,由于 BoneCP 被 HikariCP 替代,并且已经不再更新,所以对 BoneCP 没有进行过多研究。Proxool 网上有评测说在并发较高的情况下会出错,且使用的人较少,所以对 Proxool 也没有进行过多研究。Druid的功能比较全面,且扩展性较好,比较方便对 Jdbc 接口进行监控跟踪等。C3p0 历史悠久,代码及其复杂,不利于维护。并且存在 Deadlock 的潜在风险。

    综合结论:

    1:性能方面 HikariCP > Druid > Tomcat-jdbc > Dbcp > C3p0 。hikariCP的高性能得益于最大限度的避免锁竞争。

    2:Druid 功能最为全面,sql拦截等功能,统计数据较为全面,具有良好的扩展性。

    3:综合性能,扩展性等方面,可考虑使用 Druid 或者 HikariCP连接池。

    4:可开启 prepareStatement 缓存,对性能会有大概 20% 的提升。

    上面列举了几种开源的连接池,其实还有商业中间件连接池,比如 weblogic 和 websphere 等中间件连接池,这些连接池功能强大,稳定性好,性能优秀,而且监控到位。

  • 相关阅读:
    Guava Cache,Java本地内存缓存使用实践
    Guava-retry,java重试组件
    [leetcode] 31. 下一个排列
    [leetcode] 30. 与所有单词相关联的字串(cn第653位做出此题的人~)
    [leetcode] 29. 两数相除
    [leetcode] 28. 实现strStr()
    [leetcode] 27. 移除元素
    [leetcode] 26. 删除排序数组中的重复项
    [leetcode] 25. k个一组翻转链表
    [leetcode] 24. 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/cnjavahome/p/8393411.html
Copyright © 2011-2022 走看看