Appearance
三、全新JDBC扩展提升
1、自增长主键回显实现
- java程序获取插入数据时mysql维护自增长维护的主键id值,这就是主键回显
- 作用: 在多表关联插入数据时,一般主表的主键都是自动生成的,所以在插入数据之前无法知道这条数据的主键,但是从表需要在插入数据之前就绑定主表的主键,这时可以使用主键回显技术:
java
/**
* 返回插入的主键!
* 主键:数据库帮助维护的自增长的整数主键!
*
* @throws Exception
*/
@Test
public void returnPrimaryKey() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc?user=root&password=mac_root");
//3.编写SQL语句结构
String sql = "insert into t_user (account,password,nickname) values (?,?,?);";
//4.创建预编译的statement,传入SQL语句结构
/**
* TODO: 第二个参数填入 1 | Statement.RETURN_GENERATED_KEYS
* 告诉statement携带回数据库生成的主键!
*/
PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
//5.占位符赋值
statement.setObject(1, "tomcat");
statement.setObject(2, "123456");
statement.setObject(3, "汤姆猫");
//6.执行SQL语句 【注意:不需要传入SQL语句】 DML
int i = statement.executeUpdate();
//7.结果集解析
System.out.println("i = " + i);
//一行一列的数据!里面就装主键值!
ResultSet resultSet = statement.getGeneratedKeys();
resultSet.next();
int anInt = resultSet.getInt(1);
System.out.println("pk = " + anInt);
//8.释放资源
statement.close();
connection.close();
}
2、批量数据插入性能提升
- 功能需求
- 批量数据插入优化
- 提升大量数据插入效率
- 功能实现
Java
/**
* 批量细节:
* 1.url?rewriteBatchedStatements=true
* 2.insert 语句必须使用 values
* 3.语句后面不能添加分号;
* 4.语句不能直接执行,每次需要装货 addBatch() 最后 executeBatch();
* <p>
* 批量插入优化!
*
* @throws Exception
*/
@Test
public void batchInsertYH() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc?rewriteBatchedStatements=true",
"root", "mac_root");
//3.编写SQL语句结构
String sql = "insert into t_user (account,password,nickname) values (?,?,?)";
//4.创建预编译的statement,传入SQL语句结构
/**
* TODO: 第二个参数填入 1 | Statement.RETURN_GENERATED_KEYS
* 告诉statement携带回数据库生成的主键!
*/
long start = System.currentTimeMillis();
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 0; i < 10000; i++) {
//5.占位符赋值
statement.setObject(1, "ergouzi" + i);
statement.setObject(2, "lvdandan");
statement.setObject(3, "驴蛋蛋" + i);
//6.装车
statement.addBatch();
}
//发车! 批量操作!
statement.executeBatch();
long end = System.currentTimeMillis();
System.out.println("消耗时间:" + (end - start));
//8.释放资源
connection.close();
}
3、 jdbc中数据库事务实现
1、事务概念
java
// 事务概念
数据库事务就是一种SQL语句执行的缓存机制,不会单条执行完毕就更新数据库数据,最终根据缓
存内的多条语句执行结果统一判定!
一个事务内所有语句都成功及事务成功,我们可以触发commit提交事务来结束事务,更新数据!
一个事务内任意一条语句失败,及事务失败,我们可以触发rollback回滚结束事务,
数据回到事务之前状态!
举个例子:
临近高考,你好吃懒做,偶尔还瞎花钱,父母也只会说'你等着!',待到高考完毕!
成绩600+,翻篇,庆祝!
成绩200+,翻旧账,男女混合双打!
//优势
允许我们在失败情况下,数据回归到业务之前的状态!
//场景
一个业务涉及多条修改数据库语句!
例如: 经典的转账案例,转账业务(加钱和减钱)
批量删除(涉及多个删除)
批量添加(涉及多个插入)
// 事务特性
1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
// 事务类型
自动提交 : 每条语句自动存储一个事务中,执行成功自动提交,执行失败自动回滚! (MySQL)
手动提交: 手动开启事务,添加语句,手动提交或者手动回滚即可!
// sql开启事务方式
针对自动提交: 关闭自动提交即可,多条语句添加以后,最终手动提交或者回滚! (推荐)
SET autocommit = off; //关闭当前连接自动事务提交方式
# 只有当前连接有效
# 编写SQL语句即可
SQL
SQL
SQL
#手动提交或者回滚 【结束当前的事务】
COMMIT / ROLLBACK ;
手动开启事务: 开启事务代码,添加SQL语句,事务提交或者事务回滚! (不推荐)
// 呼应jdbc技术
try{
connection.setAutoCommit(false); //关闭自动提交了
//注意,只要当前connection对象,进行数据库操作,都不会自动提交事务
//数据库动作!
//statement - 单一的数据库动作 c u r d
connection.commit();
}catch(Execption e){
connection.rollback();
}
2、建表
mysql
-- 继续在 xx_jdbc 的库中创建银行表
CREATE TABLE t_bank(
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '账号主键',
account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',
money INT UNSIGNED COMMENT '金额,不能为负值') ;
INSERT INTO t_bank(account,money) VALUES
('ergouzi',1000),('lvdandan',1000);
3、BankDao
java
package com.xx;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @Author: xueqimiao
* @Date: 2023/1/4 09:51
*/
public class BankDao {
/**
* 加钱方法
*
* @param account
* @param money
* @param connection 业务传递的connection和减钱是同一个! 才可以在一个事务中!
* @return 影响行数
*/
public int addMoney(String account, int money, Connection connection) throws ClassNotFoundException, SQLException {
String sql = "update t_bank set money = money + ? where account = ? ;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值
preparedStatement.setObject(1, money);
preparedStatement.setString(2, account);
//发送SQL语句
int rows = preparedStatement.executeUpdate();
//输出结果
System.out.println("加钱执行完毕!");
//关闭资源close
preparedStatement.close();
return rows;
}
/**
* 减钱方法
*
* @param account
* @param money
* @param connection 业务传递的connection和加钱是同一个! 才可以在一个事务中!
* @return 影响行数
*/
public int subMoney(String account, int money, Connection connection) throws ClassNotFoundException, SQLException {
String sql = "update t_bank set money = money - ? where account = ? ;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//占位符赋值
preparedStatement.setObject(1, money);
preparedStatement.setString(2, account);
//发送SQL语句
int rows = preparedStatement.executeUpdate();
//输出结果
System.out.println("减钱执行完毕!");
//关闭资源close
preparedStatement.close();
return rows;
}
}
4、BankService
java
package com.xx;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* @Author: xueqimiao
* @Date: 2023/1/4 09:49
*/
public class BankService {
/**
* 转账业务方法
*
* @param addAccount 加钱账号
* @param subAccount 减钱账号
* @param money 金额
*/
public void transfer(String addAccount, String subAccount, int money) throws ClassNotFoundException, SQLException {
System.out.println("addAccount = " + addAccount + ", subAccount = " + subAccount + ", money = " + money);
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");
int flag = 0;
//利用try代码块,调用dao
try {
//开启事务(关闭事务自动提交)
connection.setAutoCommit(false);
BankDao bankDao = new BankDao();
//调用加钱 和 减钱
bankDao.addMoney(addAccount, money, connection);
System.out.println("--------------");
bankDao.subMoney(subAccount, money, connection);
flag = 1;
//不报错,提交事务
connection.commit();
} catch (Exception e) {
//报错回滚事务
connection.rollback();
throw e;
} finally {
connection.close();
}
if (flag == 1) {
System.out.println("转账成功!");
} else {
System.out.println("转账失败!");
}
}
}
5、BankTest
java
package com.xx;
import org.junit.Test;
/**
* @Author: xueqimiao
* @Date: 2023/1/4 09:48
*/
public class BankTest {
@Test
public void testBank() throws Exception {
BankService bankService = new BankService();
bankService.transfer("ergouzi", "lvdandan",
500);
}
}