一、数据库的事务
-
将整个事务看成一个整体,要么同时执行成功,要么同时执行失败
start transaction ; 开启事务
如果执行过程中不存在问题,事务提交:commit;
如果执行过程中有问题:回滚事务:rollback ;(回滚到开启事务时的状态)
举例:
-- 创建一个账户表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT ,
NAME VARCHAR(10),
balance INT
) ;
INSERT INTO account(NAME,balance) VALUES('zhangsan',1000),('lisi',1000) ;
-- 张三要给李四转账500
-- 这个业务操作需要执行两次sql才能完成
-- 张三-500
UPDATE account SET balance = balance - 500 WHERE id = 1 ;
中间出问题了
-- 李四+500
UPDATE account SET balance = balance + 500 WHERE id = 2 ;
- 问题:没有使用事务管理起来,造成了我们的整个业务操作只有zhangsan-500了,而lisi没有执行sql
不安全问题!
开启事务:start tansaction ;
-- select @@autocommit; -- @@在MySQL是一个全局变量:查看当前的事务提交状态码:默认是1(自动提交)
-- 可以通过 set @@autocommit = 0 ; 取消自动提交
- 什么时候时使用Transaction管理?
当一个业务操作需要频繁的操作SQL(两个或者多个以上的增删改),
这个时候需要使用事务管理,防止多个SQL执行过程中存在异常,导致和预期值不同!
以上代码优化:
-- 将转账业务的这个sql语句使用事务管理 (insert into,update,delete :都可以使用管理起立)
START TRANSACTION ;
-- 如果转账中出现问题了 必须回滚(默认情况下:回滚到开启事务时的状态)
-- 张三-500
UPDATE account SET balance = balance - 500 WHERE id = 1 ;
-- 此处有问题了
-- 李四+500
UPDATE account SET balance = balance + 500 WHERE id = 2 ;
-- 必须提交事务:如果没有提交事务(下次查询的时候:依然转账之前的状态 )
COMMIT ;
-- rollback ; -- (如果存在问题就要回滚)事务回滚
SELECT * FROM account ;
- 事务的特性:
原子性:每一个事务是独立的,不可再拆分.事务的执行过程中多个sql要么同时执行成功,要么同时失败
一致性:事务执行前和执行后:总量保持不变
隔离性:事务和事务之前是独立(业务和业务之间不相互影响)
持久性:事务对sql的执行是永久性的(提交事务之后)! - 事务的隔离级别:隔离级别不同,引发线程安问题不同:
脏读:一个事务读取到另一个没有提交的事物(非常严重的!)
读未提交 read uncommitted :不能够防止脏读(安全性最差)
读已提交 read committed :能够有效防止脏读,但是不可重复读防止不了
(两次读取的内容不一样!)
可重复读 repeatable read (mysql就是这个级别)
串行化 serializable - SELECT @@tx_isolation;-- 查看事务的隔离级别
– set global transaction isolation level 级别名称;设置级别
二、JDBC
- jdbc涉及到的API
1)java.sql.DriverManager 类 :驱动管理类 :管理jdbc的驱动类 com.mysql.jdbc.Driver
管理一组诸如JDBC的驱动程序(驱动服务) 类似于 计算机上的那些驱动管理器
涉及的方法:
public static Connection getConnection(String url, String user, String password)
获取数据库连接对象
参数1:url地址(jdbc协议 + mysql协议)
jdbc:mysql://localhost:3306/myee_2104
jdbc: jdbc协议
mysql://(mysql协议)
localhost:3306 (域名:端口号)
连接的具体的数据库名
参数2:user: 用户名(root)
参数3:password:密码
注册驱动
public static void registerDriver(Driver driver) :形参需要的是java.sql.Driver它的子实现类对象
com.mysql.jdbc.Driver
通过导入的驱动jar包
class Driver implements java.sql.Drvier{
public Driver() throws SQLException {
}
只要这个类一加载
static {
try {
DriverManager.registerDriver(new Driver()); //注册驱动了
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
2)java.sql.Connection:接口 与数据库的特定连接会话对象
它可以管理事务,针对事务提供一些功能:
void setAutoCommit(boolean autoCommit):参数为true,表示自动提交事务(默认的)
为false,表示关闭自动提交事务
void rollback():回滚事务,释放连接到对象,并回滚到开启事务时的状态
void commit()throws SQLException:提交事务
获取执行对象以及预编译对象
Statement createStatement() throws SQLException: 获取执行对象
PreparedStatement prepareStatement(String sql):通过预编译sql语句获取预编译对象
预编译的sql----参数化sql (?:占位符号)
String sql = "update account set balance = balance - ? where id = ?;
3)Statement:java.sql包下的接口
执行静态 SQL 语句并返回它所生成结果的对象。
int executeUpdate(String sql):执行静态sql语句
执行DDL,DML 都可以
ResultSet executeQuery(String sql):执行DQL语句
"select * from account"
4)java.sql.PreparedStatement:预编译对象
有一些功能:
ResultSet executeQuery():不带参:sql已经编译了,执行DQL语句
select...
int executeUpdate():执行参数化的sql语句:
insert into,,,
delete...
update....
5)java.sql.ResultSet:
表示的数据库的结果集数据表
通过这个接口可以实现 查询结果(多条,还是单条记录),都可以ReulstSet遍历结果
然后就可以封装实体
方法:
boolean next():将光标向前移动一行(前一行存在有效数据) :true,向前一行
User表 User类
id 字段 id属性
name 字段 name属性
address字段 address属性
- JDBC原生的操作步骤:
1)导入mysql驱动jar包
2)加载驱动
3)创建数据库的连接对象
4)准备好sql语句
5)通过数据库的连接对象获取执行对象:Statement
6)更新 或者查询(执行sql语句)
7)获取结果并释放资源
举例:
public class JdbcDemo {
public static void main(String[] args) throws Exception {
//1)导入mysql驱动jar包
//2)加载驱动 :为了保证向下兼容性:DriverManager :驱动管理类 不用他
Class.forName("com.mysql.jdbc.Driver") ;
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//3)创建数据库的连接对象
// public static Connection getConnection(
// String url,:url地址:连接的mysql的哪个数据库
// String user, :用户名
// String password) mysql的 密码
Connection conn = DriverManager.getConnection(
"jdbc:mysql:///myee_2104",
"root",
"123456"
);
System.out.println(conn);
System.out.println("准备执行...");
//4)准备好sql语句
String sql = "update account set balance = balance - 500 where id = 13" ;
//5)通过数据库的连接对象获取执行对象:Statement
//Statement createStatement()throws SQLException
Statement stmt = conn.createStatement() ;
System.out.println(stmt);
//6)执行
//int executeUpdate(St
// ring sql)throws SQLException
int count = stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
System.out.println("修改成功...");
//释放资源
stmt.close();
conn.close();
}
}
举例:
/*使用Statement执行DDL语句
* 创建一个tea表
* DML语句*/
public class JdbcDemo2 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver") ;
//获取数据库的链接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/myee_2104",
"root",
"123456"
);
//获取执行对象
stmt = conn.createStatement();
//准备sql
//DDL
/* String sql ="CREATE TABLE tea(" +
" id INT PRIMARY KEY AUTO_INCREMENT," +
" NAME VARCHAR(10), " +
" gender VARCHAR(3)," +
" address VARCHAR(10)," +
" salary INT" +
"); " ;*/
//DML语句
String sql = "insert into tea (name,gender,address,salary) values('刘备','男','西安市',8000)" ;
System.out.println(sql);
//执行sql
int count = stmt.executeUpdate(sql);
System.out.println(count);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
举例:
/* 工具类:
*
* 封装获取连接对象的功能
* 关闭资源:封装一个close()
* /
举例:
jdbc.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/myee_2104
user=root
password=123456
public class JdbcUtils {
private static String url = null ; //url地址
private static String user = null ;//用户名
private static String password = null ;//密码
private static String driver = null ;//驱动
//模仿com.mysql.jdbc.Driver 加载driver类的时候提供了静态代码块:
//注册驱动
//也可以加载JdbcUtils这个类的时候,提供一个静态代码块
static{
try {
//通过读取配置文件获取url,user,password,driver
//创建属性集合类对象
Properties prop = new Properties() ;
//读取配置文件夹
InputStream inputStream =
JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
prop.load(inputStream);
System.out.println(prop);
//通过key获取value
url = prop.getProperty("url");
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
driver = prop.getProperty("driver") ;
//加载驱动
Class.forName(driver) ;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private JdbcUtils(){} //构造私有化
//封装一个获取连接对象的功能:静态功能
public static Connection getConnection(){
Connection conn = null ;
try {
conn = DriverManager.getConnection(url, user, password);
return conn ;
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭资源
//DDL/DML语句的增删改---->返回int,影响的行数 DDL语句,返回0
public static void close(Statement stmt,Connection conn) {
close(null,stmt,conn);
}
//针对DQL语句:查询---获取结果集:ResultSet
public static void close(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!= null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!= null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//测试是否能够获取Connection对象
public static void main(String[] args) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
}
}
/* 加入封装好的工具类:来tea表
*/
public class Demo3 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try{
//获取连接
conn = JdbcUtils.getConnection();
//准备sql
String sql = "update tea set name = '张飞' where id = 1" ;
//获取执行对象
stmt = conn.createStatement();
//执行sql
int count = stmt.executeUpdate(sql);
System.out.println(count);
}catch (Exception e){
e.printStackTrace();
}finally {
JdbcUtils.close(stmt,conn);
}
}
}