JavaWeb-JDBC
一、什么是JDBC
JDBC:Java Database Connect, Java数据库连接。像驱动一样,使Java程序可以连接多个不同品牌的数据库。
二、如何使用JDBC
1.准备工作
创建一个名为JDBC
的数据库,创建一个用户表,表里的字段分别为id
,name
,password
,email
, birthday
。
# 创建数据库
create database jdbc;
# 创建表
create table users
(
`id` int primary key,
`name` varchar(40) comment '姓名',
`password` varchar(40) comment '密码',
`email` varchar(40) comment '邮箱',
`birthday` varchar(40) comment '出生日期'
);
# 添加内容
insert into users
values (1, '张三', '123456', 'zs@163.com', '2001-01-01'),
(2, '李四', '123456', 'ls@163.com', '2021-05-26'),
(3, '王五', '123456', 'ww@163.com', '2015-05-05');
# 查询表
select * from users;
2.使用JDBC
1.导入jar包
需要导入 mysql-connector-java,连接数据库的驱动。
<dependencies>
<dependency>
<!-- mysql驱动 -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
2.IDEA中连接数据库
注意:如果右侧没有database选项卡,可在顶部标题栏 View->Tool Windows->Database 开启。
3.配置信息
// 解决中文乱码
//jdbc:mysql://localhost:3306/数据库名?参数1&参数2
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
4.连接数据库
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
5.执行语句获取结果
方法1:
// 通过statement执行sql语句
Statement statement = connection.createStatement();
// 查询语句
String query = "select * from users;";
// 执行查询语句,返回结果集
ResultSet resultSet = statement.executeQuery(query);
// 增删改都是调用executeUpdate()方法
// int row = statement.executeUpdate(sql)
// 获取内容
while (resultSet.next()) {
System.out.println("=======分割线========");
System.out.printf(Locale.getDefault(), "id=%s%n", resultSet.getObject("id"));
System.out.printf(Locale.getDefault(), "name=%s%n", resultSet.getObject("name"));
System.out.printf(Locale.getDefault(), "password=%s%n", resultSet.getObject("password"));
System.out.printf(Locale.getDefault(), "email=%s%n", resultSet.getObject("email"));
System.out.printf(Locale.getDefault(), "birthday=%s%n", resultSet.getObject("birthday"));
}
效果:
方法2:预编译
// 插入语句
String insert = "insert into users (id, name, password, email, birthday) values (?, ?, ?, ?, ?);";
// 预先编译插入语句
PreparedStatement preparedStatement = connection.prepareStatement(insert);
// 插入具体值
// parameterIndex是从1开始
preparedStatement.setInt(1, 4);
preparedStatement.setString(2, "梁大侠");
preparedStatement.setString(3, "123456");
preparedStatement.setString(4, "leungmx0206@163.com");
preparedStatement.setDate(5, new Date(System.currentTimeMillis()));
// 执行sql
int row = preparedStatement.executeUpdate();
if (row > 0) {
System.out.println("添加数据成功!");
} else {
System.out.println("添加数据失败!");
}
效果:
6.关闭数据库,释放资源
// 关闭连接,释放资源(先开后关)
// 方法1 关闭
// resultSet.close();
// statement.close();
//方法2 关闭
preparedStatement.close();
connection.close();
三、事务
1. 什么是事务
将一条sql或一组sql放进一个批次里去执行。
2. 事务原则 ACID原则
ACID原则:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)*、持久性(Durability)
2.1 原子性
要么都成功,要么都失败!
2.2 一致性
事务前后的数据要保持完整性。
2.3 隔离性
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
2.4 持久性
事务一旦提交则不可逆,被持久化到数据库中。
2.5 隔离所导致的一些问题(脏读,幻读...)
脏读:指一个事务读取了另外一个事务未提交的数据。
虚读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致。(一般是行影响,如下图所示:多了一行)
不可重复性:在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
3. 测试事务
3.1 准备工作
创建数据
create table account
(
`id` int primary key auto_increment,
`name` varchar(30),
`money` decimal(9, 2)
);
insert into account(`name`, `money`)
values ('A', 1000),
('B', 1000),
('C', 1000);
3.2 实验
模拟A用户给B用户转账100
@Test
public void testTransaction() throws ClassNotFoundException {
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = null;
try {
connection = DriverManager.getConnection(url, username, password);
// 关闭自动提交
connection.setAutoCommit(false);
// 模拟转账
String transfer = "update account set money = money - 100 where name = 'A';";
connection.prepareStatement(transfer).executeUpdate();
// 模拟错误
int i = 1 / 0;
// 模拟转账
String update = "update account set money = money + 100 where name = 'B';";
connection.prepareStatement(update).executeUpdate();
// 提交
connection.commit();
System.out.println("转账成功!");
} catch (Exception e) {
try {
assert connection != null;
connection.rollback();
System.out.println("回滚成功!");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
System.out.println("转账失败!");
}
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
模拟错误发生,事务回滚:
发生错误后,会恢复回原来的数据。如果不写回滚,默认也是会回滚的。
去除错误,正常提交:
未关闭自动提交,模拟错误运行结果:
...
connection = DriverManager.getConnection(url, username, password);
// 关闭自动提交
// connection.setAutoCommit(false);
// 模拟转账
String transfer = "update account set money = money - 100 where name = 'A';";
connection.prepareStatement(transfer).executeUpdate();
// 模拟错误
int i = 1 / 0;
// 模拟转账
String update = "update account set money = money + 100 where name = 'B';";
connection.prepareStatement(update).executeUpdate();
...
没有关闭自动提交,也会执行sql语句。
这里参考了以下资料:
【狂神说Java】JavaWeb入门到实战(p28-p29)