一、整合SpringJDBC
1 JDBC
JDBC(Java Data Base Connectivity,Java 数据库连接)是一种用于执行 SQL 语句的 Java API,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
1.1 优点
JDBC 就是一套 Java 访问数据库的 API 规范,利用这套规范屏蔽了各种数据库 API 调用的差异性;
当 Java 程序需要访问数据库时,直接调用 JDBC API 相关代码进行操作,JDBC 调用各类数据库的驱动包进行交互,最后数据库驱动包和对应的数据库通讯,完成 Java 程序操作数据库。
1.2 缺点
直接在 Java 程序中使用 JDBC 比较复杂,需要 7 步才能完成数据库的操作:
加载数据库驱动 -> 建立数据库连接 -> 创建数据库操作对象 -> 编写SQL语句 -> 利用数据库操作对象执行数据库操作 -> 获取并操作结果集 -> 关闭连接对象和操作对象,回收资源
1.3 新技术
由于JDBC操作数据库非常复杂,所以牛人们编写了很多ORM框架,其中Hibernate、Mybatis、SpringJDBC最流行;
时间又过了N年,
又有牛人在Hibernate的基础上开发了SpringDataJPA,在Mybatis的基础上开发出了MybatisPlus。
2 SpringBoot集成SpringJDBC环境搭建
2.1 创建一个SpringBoot项目
引入 spring-boot-starter-web 、spring-boot-starter-jdbc、mysql-connector-java 者三个主要依赖;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
再引入 devtools、lombok这两个辅助依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.1.1 依赖说明
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xunyji</groupId> <artifactId>spring_jdbc</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring_jdbc</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
查看pom.xml依赖图可以知道 spring-boot-starter-jdbc 依赖了spring-jdbc、HikariCP;
spring-jdbc主要提供JDBC操作相关的接口,HikariCP就是传说中最快的连接池。
2.2 数据库准备
2.2.1 创建数据表
DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `name` varchar(32) DEFAULT NULL COMMENT '用户名', `password` varchar(32) DEFAULT NULL COMMENT '密码', `age` int DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2.2.1 配置数据源信息
坑:Spring Boot 2.1.0 中,com.mysql.jdbc.Driver 已经过期,推荐使用 com.mysql.cj.jdbc.Driver。
技巧:IDEA是可以连接数据库的哟,而且还可以反向生成对应的实体类哟;IDEA连接数据库并生成实体列参考博文
spring.datasource.url=jdbc:mysql://localhost:3306/testdemo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true spring.datasource.username=root spring.datasource.password=**** spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
2.2.3 创建实体类
版案例使用了lombok进行简化编写
package com.xunyji.spring_jdbc.model.entity; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * @author 王杨帅 * @create 2018-11-18 10:43 * @desc **/ @Data // 自动生成get、set、toString、equals、hashCode、canEaual方法 和 显示无参构造器 @Builder // 生成builder方法 @NoArgsConstructor // 生成无参构造器 @AllArgsConstructor // 自动生成所有字段的有参构造器,会覆盖无参构造器 public class User { private Long id; private String name; private Integer age; private String email; }
2.3 编写持久层
2.3.1 持久层接口
package com.xunyji.spring_jdbc.repository; import com.xunyji.spring_jdbc.model.entity.User; import org.springframework.stereotype.Repository; import java.util.List; /** * @author 王杨帅 * @create 2018-11-18 10:53 * @desc user表对应的持久层接口 **/ public interface UserRepository { Integer save(User user); Integer update(User user); Integer delete(Integer id); List<User> findAll(); User findById(Integer id); }
2.3.2 持久层实现类
技巧:在实现类中依赖注入 JdbcTemplate,它是Spring提供的用于JDBC操作的工具类。
@Autowired private JdbcTemplate jdbcTemplate;
package com.xunyji.spring_jdbc.repository.impl; import com.xunyji.spring_jdbc.comm.exception.ExceptionEnum; import com.xunyji.spring_jdbc.comm.exception.FuryException; import com.xunyji.spring_jdbc.model.entity.User; import com.xunyji.spring_jdbc.repository.UserRepository; import com.xunyji.spring_jdbc.repository.impl.resultmap.UserRowMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.List; /** * @author 王杨帅 * @create 2018-11-18 10:55 * @desc user表对应的持久层实现类 **/ @Repository public class UserRepositoryImpl implements UserRepository { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private JdbcTemplate jdbcTemplate; @Override public Boolean save(User user) { Integer saveResult = jdbcTemplate.update( "INSERT user (name, age, email) VALUES (?, ?, ?)", user.getName(), user.getAge(), user.getEmail() ); if (saveResult.equals(1)) { return true; } return false; } @Override public Boolean update(User user) throws Exception { Integer updateResult = jdbcTemplate.update( "UPDATE user SET name = ?, age = ?, email = ? WHERE id = ?", user.getName(), user.getAge(), user.getEmail(), user.getId() ); if (updateResult.equals(1)) { return true; } return false; } @Override public Boolean delete(Long id) { Integer deleteResult = jdbcTemplate.update( "DELETE FROM user WHERE id = ?", id ); if (deleteResult.equals(1)) { return true; } return false; } @Override public List<User> findAll() { return jdbcTemplate.query( "SELECT * FROM user", new UserRowMapper() ); } @Override public User findById(Long id) { try { User user = jdbcTemplate.queryForObject( "SELECT id, name, age, email FROM user WHERE id = ?", new Object[]{id}, new BeanPropertyRowMapper<>(User.class) ); return user; } catch (EmptyResultDataAccessException e) { log.info(e.getMessage()); throw new FuryException(ExceptionEnum.RESULT_IS_EMPTY); } } }
技巧:新增、更新、删除都是利用JdbcTemplate的update方法,update方法的返回值是执行成功的记录数(需在实现类中根据结果判断是否操作成功);
技巧:利用JdbcTemplate的queryForObject方法查询单条记录,利用JdbcTemplate的query查询多条记录;
技巧:利用JdbcTemplate的queryForObject方法查询单条记录时如果查询不到就会抛出EmptyResultDataAccessException,需要进行捕获。
技巧:查询记录时需要对结果集进行封装,可以直接利用BeanPropertyRowMapper实例进行封装,或者自定义一个实现了UserRowMapper的实现类
2.3.3 持久层测试类
package com.xunyji.spring_jdbc.repository.impl; import com.xunyji.spring_jdbc.model.entity.User; import com.xunyji.spring_jdbc.repository.UserRepository; import lombok.extern.slf4j.Slf4j; import org.junit.Before; 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 java.util.List; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class UserRepositoryImplTest { @Autowired private UserRepository userRepository; private User user; @Before public void init() { user = User.builder() .id(81L) .age(33) .name("warrior") .email("[email protected]") .build(); } @Test public void save() throws Exception { Boolean saveNumber = userRepository.save(user); log.info("新增结果为:" + saveNumber); } @Test public void update() throws Exception { Boolean updateResult = userRepository.update(user); log.info("更新结果为:" + updateResult); } @Test public void delete() throws Exception { Boolean delete = userRepository.delete(81L); log.info("删除结果为:" + delete); } @Test public void findById() throws Exception { User byId = userRepository.findById(8L); log.info("获取的数据信息为:" + byId); } @Test public void findAll() throws Exception { List<User> all = userRepository.findAll(); log.info("获取到的列表数据为:" + all); all.stream().forEach(System.out::println); } }
2.4 编写服务层
待更新...
2.5 编写控制层
待更新...
3 多数据源
3.1 硬编码实现【不推荐】
3.2 AOP实现【推荐】
二、整合MyBatis