Java 操作数据库
JDBC
- JDBC:(Java DataBase Connectivity),就是使用 Java 语言操作关系型数据库的一套 API。
- 本质:
- sun 公司官方定义的一套操作所有关系型数据库的规范,即接口。
- 各个数据库厂商去实现这一套接口,提供数据库驱动 jar 包。
- 我们可以使用这一套接口(JDBC)编程,真正执行的代码是驱动 jar 包中的实现类。
入门程序
- 需求:基于 JDBC 程序,执行 update 语句
update user set age = 25 where id = 1 - 步骤:
- 准备工作:创建一个 maven 项目,引入依赖;并准备数据库表 user。
- 代码实现:编写 JDBC 程序,操作数据库
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcTest {
/**
* JDBC 入门程序
*/
@Test
public void testUpdate() throws ClassNotFoundException, SQLException {
// 1. 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取数据库连接
String url = "jdbc:mysql://localhost:3306/web01";
String user = "root";
String password = "115248";
Connection connection = DriverManager.getConnection(url, user, password);
// 3. 获取 SQL 语句执行对象
Statement statement = connection.createStatement();
// 4. 执行 SQL
String sql = "update user set age = 25 where id = 1";
int count = statement.executeUpdate(sql);// DML
System.out.println("该操作受影响的行数:" + count);
// 5. 释放资源
statement.close();
connection.close();
}
}
查询数据
- 需求:基于 JDBC 执行如下 select 语句,将查询结果封装到 User 对象中。
- SQL:
select * from user where username = 'daqiao' and password = '123456' - ResultSet(结果集对象):
ResultSet rs = statement.executeQuery()- next():将光标从当前位置向前移动一行,并判断当前行是否为有效行,返回值为 boolean。
- true:有效行,当前行有数据
- false:无效行,当前行没有数据
- getXxx(...):获取数据,可以根据列的编号获取,也可以根据列名获取(推荐)。
- next():将光标从当前位置向前移动一行,并判断当前行是否为有效行,返回值为 boolean。
- 结果解析步骤:
while (resultSet.next()) {
int id = resultSet.getInt("id");
// ... 省略
}
@Test
public void testQuery(){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(URL, USER, PASSWORD);
String sql = "select * from user where username = ? and password = ?";// 预编译 SQL,防止 SQL 注入
statement = connection.prepareStatement(sql);
statement.setString(1, "daqiao");
statement.setString(2, "123456");
resultSet = statement.executeQuery();
while (resultSet.next()){
User user = new User(
resultSet.getInt("id"),
resultSet.getString("username"),
resultSet.getString("password"),
resultSet.getString("name"),
resultSet.getInt("age")
);
System.out.println(user);
}
}catch(ClassNotFoundException | SQLException e){
e.printStackTrace();
}finally{
try{
if(resultSet != null)
resultSet.close();
if(statement != null)
statement.close();
if(connection != null)
connection.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
预编译 SQL
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE username = ? AND password = ?");
ps.setString(1, "linchong");
ps.setString(2, "123456");
ResultSet resultSet = pstmt.executeQuery();
-
优势一:可以防止 SQL 注入,更安全
SQL 注入:通过控制输入来修改事先定义好的 SQL 语句,以达到执行代码对服务器进行攻击的方法。
-
优势二:性能更高
MyBatis
- MyBatis 是一款优秀的持久层框架,用于简化 JDBC 的开发。
- MyBatis 本是 Apache 的一个开源项目 iBatis,2010年这个项目由 apache 迁移到了 google code,并且改名为 MyBatis。2013年11月迁移到 Github。
- 官网:https://mybatis.org/mybatis-3/zh_CN/index.html
入门项目:使用 Mybatis 查询所有用户数据
- 准备工作:
- 创建 SpringBoot 工程、引入 Mybatis 相关依赖
- 准备数据库表 user、实体类 User
- 配置 Mybatis(在 application.properties 中数据库连接信息)
- 编写 Mybatis 程序:编写 Mybatis 的持久层接口,定义 SQL(注解 / XML)
- 提示:Mybatis 的持久层接口命名规范为 XxxMapper,也称为 Mapper 接口
package com.faxont.mapper;
import com.faxont.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper // 应用程序在运行时,会自动地为该接口创建一个实现类对象(代理对象),并且会自动将该实现类对象存入 IOC 容器 - bean
public interface UserMapper {
/**
* 查询所有用户
* @return
*/
@Select("select * from `user`")
public List<User> findAll();
}
package com.faxont;
import com.faxont.mapper.UserMapper;
import com.faxont.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class SpringbootMybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List<User> userList = userMapper.findAll();
userList.forEach(System.out::println);
}
}
数据库连接池
-
数据库连接池是个容器,负责分配,管理数据库连接(Connection)。
-
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
-
释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏。
-
优势:
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
-
标准接口:DataSource
- 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口。
- 功能:获取连接
Connection getConnection() throws SQLException;
-
常见产品:
C3P0 DBCP Druid HiKari(SpringBoot 默认)
-
Druid(德鲁伊)
- Druid 连接池是阿里巴巴开源的数据库连接池项目
- 功能强大,性能优秀,是 Java 语言最好的数据库连接池之一
-
切换数据库连接池
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.19</version>
</dependency>
# application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/web
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=1234
删除用户-delete
- 需求:根据 ID 删除用户信息
- SQL:
delete from user where id = 5; - Mapper 接口:
@Delete("delete from user where id = #{id}")
public void deleteById(Integer id);
// 返回值为影响的行数
@Delete("delete from user where id = #{id}")
public Integer deleteById(Integer id);
- 注意:DML 语句执行完毕的返回值,表示该 DML 语句执行完毕影响的行数。
- Mybatis 中的 # 号与 $ 号:
| 符号 | 说明 | 场景 | 优缺点 |
|---|---|---|---|
| # | 占位符。执行时,会将#{...}替换为?,生成预编译 SQL | 参数值传递 | 安全、性能高(推荐) |
| $ | 拼接符。直接将参数拼接在 SQL 语句中,存在 SQL 注入问题 | 表名、字段名动态设置时使用 | 不安全、性能低 |
新增用户-insert
- 需求:添加一个用户
- SQL:
insert into user(username, password, name, age) values ('zhouyu', '123456', '周瑜', 20); - Mapper 接口:
@Insert("insert into user(username, password, name, age) values (#{username}, #{password}, #{name}, #{age})")
public void insert(User user);
修改用户-update
- 需求:根据 ID 更新用户信息
- SQL:
update user set username = 'zhouyu', password = '123456', name = '周瑜', age = 20 where id = 1 - Mapper 接口:
@Update("update user set username=#{username}, password=#{password}, name=#{name}, age=#{age} where id=#{id}")
public void update(User user);
查询用户-select
- 需求:根据用户名和密码查询用户信息
- SQL:
select * from user where username = 'zhouyu' and password = '666888'; - Mapper 接口:
- @Param 注解的作用是为接口的方法形参起名字的。
@Select("select * from user where username=#{username} and password=#{password}")
public User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
- 说明:基于官方骨架创建的 springboot 项目中,接口编译时会保留方法形参名,@Param注解可以省略(#{形参名})。
@Select("select * from user where username=#{uname} and password=#{pwd}")
public User findByUsernameAndPassword(String uname, String pwd);
XML 映射配置
- 在 Mybatis 中,既可以通过注解配置 SQL 语句,也可以通过 XML 配置文件配置 SQL 语句。
- 默认规则:
- XML 映射文件的名称与 Mapper 接口名称一致,并且将 XML 映射文件和 Mapper 接口放置在相同包下(同包同名)。
- XML 映射文件的 namespace 属性与 Mapper 接口全限定名一致。
- XML 映射文件中 sql 语句的 id 与 Mapper 接口中的方法名一致,并保持返回类型一致。
- 那在 Mybatis 的开发中,到底使用注解开发还是使用 XML 开发呢?
- 使用 Mybatis 的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的 SQL 功能,建议使用 XML 来配置映射语句。
- 官方说明:https://mybatis.net.cn/getting-started.html
辅助配置
- 配置 XML 映射文件的位置:
# application.properties
# 指定 XML 映射配置文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
- MybatisX 是一款基于 IDEA 的快速开发 Mybatis 的插件,为效率而生。
配置文件格式
- SpringBoot 项目提供了多种属性配置方式(properties、yaml、yml)。
# application.properties
# 臃肿、层级结构不清晰
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/web01
spring.datasource.username=root
spring.datasource.password=1234
# application.yaml / application.yml
# 简洁、数据为中心
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/web01
username: root
password: 1234
yml 配置文件
- 格式:
- 数值前边必须有空格,作为分隔符
- 使用缩进表示层级关系,缩进时,不允许使用 Tab 键,只能用空格(idea 中会自动将 Tab 转换为空格)
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
#表示注释,从这个字符一直到行尾,都会被解析器忽略
- 定义对象 / Map集合:
user:
name: 张三
age: 18
password: 123456
- 定义数组 / List / Set 集合:
hobby:
- java
- game
- sport
- 注意:在 yml 格式的配置文件中,如果配置项的值是以0开头的,值需要使用 ' ' 引起来,因为以0开头在 yml 中表示8进制的数据。

浙公网安备 33010602011771号