MYSQL操作详细操作
1. 什么是事物?
要么都成功,要么都失败
1.SQL执行 A 给 B 转账 A 1000 ---->200 B 200
2.SQL执行 B收到A的钱 A 800 -----> B 400
将一组SQL放在一个批次中去执行
事物原则:ACID 原则 原子性(atomicity),一致性(consistency),隔离性(isolation),持久性(durability) (脏读,幻读。。。)
-
Atomicity(原子性):要么都成功,要么都失败。
-
一致性(Consistency):事务前后的数据完整性要保持一致。
-
持久性(durability):事务一旦提交则不可逆,被持久化到数据库中!
-
隔离性(isolation):事物的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启事务,不能被其他事物的操作数据所干扰之间要相互隔离。
-
隔离会导致的问题:
-
脏读
-
不可重复读
-
幻读
-
2.执行事务
-- =========事物==========
-- mysql 是默认开启事物自动提交的
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启
-- 手动处理事务
SET autocommit = 0 -- 关闭自动条件
-- 事务开启
START TRANSACTION -- 标记一个事务开始,从这个之后 sql 都处在同一事务
INSERT xx
INSERT xx
-- 提交,持久化(成功!)
COMMIT
-- 回滚,回到原来的样子(失败)
ROLLBACK
-- 事务结束
SET autocommit = 1 -- 开启自动提交
-- 了解
SAVEPOINT 保存点名 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点
模拟场景:
-- === 模拟转账 ===
INSERT INTO `shop`.`account`(`name`,`money`)VALUES('A',2000.00),('B',10000.00);
-- 模拟转账:事务
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION -- 开启一个事务(一组事务)
UPDATE `shop`.`account` SET `money` = `money` - 500 WHERE `name` = 'A'; -- A减500
UPDATE `shop`.`account` SET `money` = `money` + 500 WHERE `name` = 'B'; -- B加500
COMMIT; -- 提交事务,就被持久化了!
ROLLBACK; -- 回滚
SET autocommit = 1; -- 恢复默认值
3.索引
MySQL官方对索引的定义为:索引 (Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。
-
索引的分类
-
主键索引(PRIMARY KEY)
-
唯一的标识:主键不可重复,只能有一个列作为主键。
-
-
唯一索引(UNIQUE KEY)
-
避免面重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引。
-
-
常规索引 ( KEY / INDEX )
-
默认的,Index、Key关键字设置
-
-
全文索引( FullText )
-
在特定数据库引擎下才有,MYSAM
-
-
-
基础语法:
-- 索引的使用
-- 1、在创建表的时候给字段增加索引
-- 2、创建完毕后,增加索引
-- 显示所有的索引信息
SHOW INDEX FROM `school`.`student`
-- 增加一个索引
ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `name`(`name`)
-- EXPLAIN 分析sql执行的状况
EXPLAIN SELECT * FROM `school`.`student` -- 非全文索引
EXPLAIN SELECT * FROM `school`.`student` WHERE MATCH(`name`) AGAINST ('yi')
4.测试索引
INSERT INTO `school`.`app_user`(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('用户',2),'173@11.com',CONCAT('18',FLOOR(RAND()*100000000)),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100)),
(CONCAT('用户',3),'173@11.com',CONCAT('18',FLOOR(RAND()*100000000)),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100)),
(CONCAT('用户',4),'173@11.com',CONCAT('18',FLOOR(RAND()*100000000)),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100)),
(CONCAT('用户',5),'173@11.com',CONCAT('18',FLOOR(RAND()*100000000)),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100)),
(CONCAT('用户',6),'173@11.com',CONCAT('18',FLOOR(RAND()*100000000)),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SELECT * FROM `school`.`app_user` WHERE `name` = '用户1';
EXPLAIN SELECT * FROM `school`.`app_user` WHERE `name` = '用户1';
CREATE INDEX id_name ON `school`.`app_user`(`name`)
EXPLAIN SELECT * FROM `school`.`app_user` WHERE `name` = '用户1';
索引在小数据的时候,用处不打。但是在大数据的时候,区别十分明显~
5.索引原则
-
索引不是越多越好。
-
不要对进程变动数据加索引。
-
小数据量的表不需要加索引。
-
索引一般加载常用来查询的字段上。
索引的数据结构:
Hash 类型的索引
Btree:InnoDB的默认数据结构~
阅读:
数据库备份。权限管理。数据库的归约,三大范式。JDBC。
6.权限管理和备份
-
用户管理:
SQL命令操作:
1. 用户表:mysql.user
1. 本质:读这张表进行增删改查
-- 创建用户
CREATE USER yuan1 IDENTIFIED BY '123456';
-- 修改密码 (修改当前用户密码)
SET PASSWORD = PASSWORD('123456');
-- 修改密码(修改指定用户密码)
SET PASSWORD FOR yuan =PASSWORD('111111');
-- 重命名 RENAME USER 原来名字 TO 新名字
RENAME USER yuan TO yuan2
-- 用户授权 ALL PRIVILEGES 全部的权限,库,表
-- ALL PRIVILEGES 除了给别人授权,其他都能干
GRANT ALL PRIVILEGES ON *.* TO yuan
-- 查询权限
SHOW GRANTS FOR yuan -- 查看指定用户权限
SHOW GRANTS FOR root@localhost
-- ROOT用户权限;GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
-- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM yuan
-- 删除用户
DROP USER yuan
7.MySQL备份
为什么要备份:
-
保证重要的数据不丢失。
-
数据转移
MySQL数据库备份的方式
-
直接拷贝物理文件
-
在Sqlyog 这种可视化工具中手动导出:
-
在想要导出的表或者库中,右键,选择备份或导出。
-
使用命令行到处 mysqldump 命令行使用
# mysqldump -h 主机 -u 用户名 -p密码 数据库 表名 > 物理磁盘位置、文件名
mysqldump -h localhost -uroot -p123456 school student >D:/a.sql
# mysqldump -h 主机 -u 用户名 -p密码 数据库 表1 表2 表3 > 物理磁盘位置、文件名
# 导入
# 登录的情况下,切换到指定的数据库
# source 备份文件
souce D:/a.sql
#非登录情况下
mysql -u用户名 -p密码 库名< 备份文件假设你要备份数据库,防止数据丢失。
把数据库给朋友!sql文件给别人即可
8.规范数据库设计
-
为什么需要设计?
当数据库比较复杂的时候,我们需要设计。
糟糕的数据库设计:
-
数据冗余,浪费空间。
-
数据插入和删除都会麻烦。异常【屏蔽使用物理瓦检】
-
程序性能差
良好的数据库设计:
-
节省内存空间
-
保证数据库完整性
-
方便我们开发系统
软件开发中,关于数据库的设计
* 分析需求:分析业务和需要处理的数据库的需求
* 概要设计:设计关系图 E- R 图设计数据库步骤:(个人博客类似)
-
收集信息、分析需求
** 用户表(用户登录注销,用户个人信息,写博客,创建分类)
** 分类表(文章分类,谁创建的)
** 文章表(文章的信息)
** 友链表(友链信息)
** 自定义表(系统信息,某个关键的字,或者一些主字段)
** 说说表(发表心情.. id... content )
key:value
-
标识实体(把需求落地到每个字段)
-
标识 实体之间的关系
** 写博客:user—> blog
** 创建分类:user—> category
** 关注:user—>user
** 友链:links
** 评论:user-user-blog
-
-
9.三大范式
为什么需要数据规范化?
-
信息重复
-
更新异常
-
插入异常
-
无法正常显示信息
-
-
删除异常
-
丢失有效的信息
-
三大范式:
第一范式(1NF):
原子性:保证每一列不可再分。
第二范式(2NF):
前提:满足第一范式。每张表只描述一件事情。
第三范式(3NF):
前提:满足第一范式和第二范式。
第三范式需要确保数据表中的每一列数据都和主键直接相关。而不能间接相关。
(规范数据库的设计)
规范性 和 性能的问题
关联查询的表不得超过三张表
-
考虑商业化的需求和目标。(成本,用户体验!)数据库性能更加重要。
-
在规范性能问题的时候,适当考虑规范性。
-
故意给某些表增加一些字段(从多表查询变为单表查询)
-
故意增加一些计算列(从大数据量,降低为小数据量的查询:索引)
10.JDBC(重点)
-
数据库驱动:程序需要通过数据库驱动连接上数据库,再和数据库打交道!
-
JDBC:SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)规范,俗称JDBC。这些规范的实现由具体的厂商去做!
对于开发人员,我们只需要掌握JDBC接口操作即可。
java.sql
javax.sql
还需要导入一个数据库驱动包 mysql-connector-java-5.1.47.jar
11.第一个JDBC程序
-
创建一个项目
-
导入数据库
copy进lib后右键 Add as library
-
代码建立连接
import java.sql.*;
// 我的第一个JDBC 程序
public class JdbcFirst {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法,加载驱动
// 2.连接信息 用户信息和 url
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&charcterEncoding=utf8&useSSL=true";
// String url = "jdbc:mysql://localhost:3306";
String username= "root";
String password = "123456";
// 3.连接成功,数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url,username,password);
// 4.执行SQL的对象 Statement 执行sql对象
Statement statement=connection.createStatement();
// 5.执行SQL的对象 去 执行SQL,可能存在结果,查看返回的结果
String sql = "SELECT * FROM `jdbcstudy`.`users`";
ResultSet resultSet=statement.executeQuery(sql); // 查看返回的结果集 结果封住了我们查出的全部结果
while(resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("name="+resultSet.getObject("name"));
System.out.println("password="+resultSet.getObject("password"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birth="+resultSet.getObject("birthday"));
System.out.println("==========");
}
// 6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结:
-
加载驱动。Class.forName("com.mysql.cj.jdbc.Driver")
-
连接数据库DriverManager。 Connection connection = DriverManager.getConnection(url,username,password);
-
获得sql的对象。 Statement Statement statement=connection.createStatement();
-
获得返回的结果集。ResultSet resultSet=statement.executeQuery(sql);
-
释放连接。.close()
DriverManager
-
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法,加载驱动
// 3.连接成功,数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url,username,password);
// connection 代表数据库
// 数据库设置自动提交
// 事务提交
// 事务回滚
// connection代表数据库所能干的事
connection.rollback();
connection.commit();
connection.setAutoCommit();
URL
// 2.连接信息 用户信息和 url
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&charcterEncoding=utf8&useSSL=true";
// mysql -- 3306
// jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3
// oralce -- 1521
//jdbc:oracle:thin:@localhost:1521:sid
Statement 执行SQL的对象 PrepareStatement
String sql = "SELECT * FROM `jdbcstudy`.`users`"; //编写SQL
statement.executeQuery(); // 查询操作返回 Result
statement.execute(); // 执行任何SQL
statement.executeUpdate() // 更新、插入、删除,返回一个受影响的函数
ResultSet 查询的结果集:封装了所有的查询结果
resultSet.getObject() //在不知道列的类型
// 如果知道列的类型就用指定类型
resultSet.getString()
resultSet.getInt()
resultSet.getFloat()
resultSet.getDate()
resultSet.getObject()
...
遍历,指针
resultSet.beforeFirst() // 移动到最前面
resultSet.afterLast() // 移动到最后面
resultSet.next() // 移动到下一个数据
resultSet.previous() // 移动到前一行
resultSet.absolute(row) // 移动到指定行
释放资源
// 6.释放连接
resultSet.close();
statement.close();
connection.close();
12.statement对象
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement str = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = str.executeUpdate(sql);
if(num > 0){
System.out.println("输入成功!!")
}
CRUD操作 - delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement str = connection.createStatement();
String sql = "delete from user where id = 1";
int num = str.executeUpdate(sql);
if(num > 0){
System.out.println("删除成功!!")
}
CRUD操作 - update
使用executeUpdate(String sql)方法完成数据修改操作,示例操作:
Statement str = connection.createStatement();
String sql = "update user set name='' where id = 1";
int num = str.executeUpdate(sql);
if(num > 0){
System.out.println("修改成功!!")
}
CURD操作 - read
使用executeQuery(String sql)方法完成数据查询操作,示例操作:
Statement str = connection.createStatement();
String sql = "select * from users where id = 1";
int num = str.executeQuery(sql);
if(num.next()){
System.out.println("查询成功!!")
}
代码实现
-
提取工具类
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456package com.yuan.lesson02.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dp.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
// 1.驱动只用加载一次
Class.forName(driver);
}catch (IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//释放连接资源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(st != null){
try {
st.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
} -
编写增删改查 executeUpdate()
package com.yuan.lesson02.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.yuan.lesson02.utils.JdbcUtils;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs =null;
JdbcUtils JdbcUtils = new JdbcUtils();
try {
conn = JdbcUtils.getConnection(); //获取数据库连接
st = conn.createStatement(); // 获取SQL执行对象
String sql = "INSERT INTO `jdbcstudy`.`users`(`id`,`name`,`password`,`email`,`birthday`) VALUES(5,'HEQI','123456','HQ@163.com','1990-11-11')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}package com.yuan.lesson02.utils;
import com.yuan.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs =null;
JdbcUtils JdbcUtils = new JdbcUtils();
try {
conn = JdbcUtils.getConnection(); //获取数据库连接
st = conn.createStatement(); // 获取SQL执行对象
String sql = "DELETE FROM `jdbcstudy`.`users` WHERE `id`=5";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("删除成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs =null;
JdbcUtils JdbcUtils = new JdbcUtils();
try {
conn = JdbcUtils.getConnection(); //获取数据库连接
st = conn.createStatement(); // 获取SQL执行对象
String sql = "UPDATE `jdbcstudy`.`users` SET `name`='nihao' WHERE `id`=4";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("更新成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
-
查询
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
// SQL
String sql = "select * from `jdbcstudy`.`users` where id = 1";
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getObject("name"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}SQL 注入问题
sql存在漏洞,会被攻击导致内容泄露。SQL会被拼接 or
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
login(" 'or '1=1'","'or '1=1'");
}
// 登录业务
public static void login(String username,String password){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
// SQL
String sql = "select * from `jdbcstudy`.`users` where `name` = '"+username+"' AND `password`='"+password+"'" ;
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getObject("name"));
System.out.println(rs.getObject("password"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
13.PreparedStatement对象
PreparedStatement可以防止SQL注入,效率更好!
-
新增
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestInsert {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用?占位符代替参数
String sql = "INSERT INTO `jdbcstudy`.`users`(`id`,`name`,`password`,`email`,`birthday`) VALUES(?,?,?,?,?)";
st = conn.prepareStatement(sql); //预编译SQL,先写sql,然后不执行
// 手动给参数赋值
st.setInt(1,5); //id
st.setString(2,"heqi");
st.setString(3,"123456");
st.setString(4,"hq@163.com");
//转化时间戳 sql.Date 数据库用的
// util.Date Java new Date().getTime() 获得时间戳
st.setDate(5,new java.sql.Date(new Date(1977,10,10).getTime()));
// 执行
int i= st.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
-
删除
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用?占位符代替参数
String sql = "delete from `jdbcstudy`.`users` where id=?";
st = conn.prepareStatement(sql); //预编译SQL,先写sql,然后不执行
// 手动给参数赋值
st.setInt(1,5);
// 执行
int i= st.executeUpdate();
if(i>0){
System.out.println("删除成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
-
改变
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用?占位符代替参数
String sql = "update `jdbcstudy`.`users` set `name`=? where id=?";
st = conn.prepareStatement(sql); //预编译SQL,先写sql,然后不执行
// 手动给参数赋值
st.setString(1,"heqi2");
st.setInt(2,5);
// 执行
int i= st.executeUpdate();
if(i>0){
System.out.println("修改成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
-
查找
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn=JdbcUtils.getConnection();
String sql = "select * from `jdbcstudy`.`users` where id=?";
st = conn.prepareStatement(sql);
st.setInt(1,1);
// 执行
rs = st.executeQuery();
if(rs.next()){
System.out.println(rs.getObject("name"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.release(conn,st,rs);
}
}
}
14.使用IDEA连接数据库
连接成功后可以选择数据库。
双击数据库,查询数据内容
更新数据
编写SQL
切换数据库
连接失败,查看原因
要么都成功,要么都失败
ACID原则
原则性:要么全部完成,要么都不完成。
一致性:总数不变。
隔离性:多个进程互不干扰。
持久性:一旦提交不可逆,持久化到数据库。
隔离性问题:
脏读:一个事务读取了另一个没有提交的事务。
不可重复读:在同一个事务内,重复读取表中的数据,表数据发生改变。
虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致。
代码实现
-
开启事务(conn.setAutoCommit(false); //**开启事务)
-
一组业务执行完毕,提交事务。
-
可以在catch语句中显示的定义,回滚语句,但默认失败就会回滚
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st= null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交,自动会开启事务
conn.setAutoCommit(false); //开启事务
String sql1="update `shop`.`account` set money = money-100 where id = 1";
st=conn.prepareStatement(sql1);
int i=st.executeUpdate();
String sql2="update `shop`.`account` set money = money+100 where id = 2";
st=conn.prepareStatement(sql2);
int s=st.executeUpdate();
//业务完成,提交事务
conn.commit();
if(i>0&&s>0){
System.out.println("成功");
}
} catch (SQLException e) {
try {
conn.rollback(); // 如果失败回滚事务
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
16.数据库连接池
数据库连接——执行完毕——释放
连接——释放 十分浪费系统资源
池化技术:准备一些预先的资源,过来连接预先准备好的
——开门——业务员:等待——服务——
常用连接数:10
最小连接数:10
最大连接数:15业务最高承载上线
等待超时:100ms
编写连接池,实现一个接口。DataSource
开源数据实现(拿来即用)
DBCP
C3P0
Druld:阿里巴巴
使用了这些数据库连接池之后,我们在项目中开发就不需要编写数据库代码了。
DBCP
需要用到的jar包
commons-dbcp-1.4 、commons-pool-1.6
C3P0
需要用到的jar包
c3p0-0.9.5.5、mchange-commons-java-0.2.19
结论
无论使用什么数据源,本质还是一样的。DataSource接口不会变,方法就不会变。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理