transaction 事务指的是一组操作,里面包含许多个单一的逻辑,只要有一个逻辑没有执行成功,那么都算失败,所有的数据回到最初的状态(回滚)
*事务存在的意义
为了确保许多逻辑必须成功,例子,银行转账。
开启事务:
start transaction
提交事务或者回滚事务
commit ; 提交事务,数据将会写道磁盘上的数据库
rollback 数据回滚,回到最初的状态
贴一个配置的时候遇到的问题:
Unknown initial character set index ‘255’ received from server. Initial client character set can be
package test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.jupiter.api.Test;
import uitl.JDBCUtil;
public class testDemo {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
@Test
public void testTransaction() {
try {
conn = JDBCUtil.getConn();
conn.setAutoCommit(false);
String sql = "update account set money = money -? where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 100);
ps.setInt(2, 1);
ps.executeUpdate();
// rs = ps.executeQuery();
// while (rs.next()) {
// String name = rs.getString("name");
// int money = rs.getInt("money");
// System.out.println(name + " -- " + money);
//
// }
int a = 10 / 0;
ps.setInt(1, -100);
ps.setInt(2, 2);
ps.executeUpdate();
// 成功就提交
conn.commit();
} catch (Exception e) {
try {
// TODO: handle exception
//中间出现了问题,所以需要回滚
e.printStackTrace();
conn.rollback();
} catch (Exception e2) {
// TODO: handle exception
}
} finally {
JDBCUtil.release(conn, ps, rs);
}
}
}
代码里面的事务,主要是针对链接来的,通过
1 conn.setAutoCommit(false)来设置自动关闭提交的设置
2 提交事务conn.commit();
3 回滚事务conn.rollback();
ACID
指的是事务中包含的逻辑不可分割
事务执行前后,数据的完整性保持一致
指的是事务在执行期间,不应该受到其他事务的影响
指的是 事务执行成功,那么数据应该持久保存到磁盘上。
不考虑隔离级别设置,那么会出现以下问题
脏读 不可重读读 幻读
脏读 : 一个事务读取到了另一个事务还未提交的数据
步骤1 设置A窗口的隔离级别,读未提交
步骤2 两个窗口都开启事务
读未提交容易造成脏读
1 在代码里面会使用事务
conn.setAutoCommit(false);
conn.cimmit();
conn.rollback();
2 事务只是针对链接对象,如果再开一个链接对象,那么是要默认的提交
3 事务是会自动提交的
读
脏读
一个事务读取到了另一个事务未提交的数据
不可重复度
一个事务读取到了另一个事务已提交的数据,造成两次前后查询结果不一致
幻读
一个事务读取到了另一个事务insert 的数据,造成前后查询结果不一致
写
丢失更新
读未提交
引发问题:脏读
读已提交
解决: 脏读, 引发: 不可重复读
可重复读
解决:脏读 不可重复读 未解决 : 幻读
可串行化
解决:脏读 不可重复读 幻读
mysql 默认的隔离级别是 可重复读
oracle 的默认隔离级别是 读已提交
可以在查询的时候,加入for update
select * from account for update;// 数据库的锁机制,排他锁
程序员自己控制
一开始在内存中开辟一块空间(集合),一开始往池子里面防止多个链接对象,后面需要链接的话,直接从赤字里面去,不要去自己创造链接了。使用完毕,记得要归还链接,确保连接对象能够循环利用
package uitl;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
//这是一个数据库连接池,一开始往池子里面放10个链接
//1 开始创建10 个链接
//2 来的程序通过getconnection 获取链接
//3 用完以后,使用addBack归还链接
//4 扩容
//sun 公司发布的连接池规范里面的名字是datasource 的接口
public class MyDataSource implements DataSource {
// 该连接池对外公布的获取链接的方法
List list = new ArrayList();
public MyDataSource() {
for (int i = 0; i < 10; i++) {
Connection conn = JDBCUtil.getConn();
list.add(conn);
}
}
@Override
public Connection getConnection() throws SQLException {
if (list.isEmpty()) {
for (int i = 0; i < 5; i++) {
Connection conn = JDBCUtil.getConn();
list.add(conn);
}
}
// remove 是移除第一个
Connection conn = list.remove(0);
return conn;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
public void addBack(Connection conn) {
list.add(conn);
}
// ------------------------------
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public T unwrap(Class iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
}
问题:
1 sun 公司给出的一套规范,但是我们自己加了一套方法addback方法把connection 返回回来所以需要额外的记一套方法
2 单例
3 无法面向接口编程
UserDao dao =new UserDaoImpl();
dao.insert();
dataSource dataSource = new MyDataSource();
因为接口里面没有顶底addBack方法
4 怎么解决 以addBack 为切入点
由于多了一个addBack方法,所以使用这个连接池的地方,需要额外记住这个方法, 还不能面向接口编程
planA 修改接口中的close 方法,原来connection 的close方法是真的关闭链接。
打算修改close 方法,以后再调用close,并不是真的关闭,而是归还链接对象
不是我们需要的方法逻辑,需要修改自己的逻辑
1 直接改源码,但是实现不了
2 继承,必须得知道这个接口的具体实现是谁,没法做
3 使用装饰者模式
4 动态代理
总结
优点
装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者模式可以提供比继承更多的灵活性。
通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点
这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
//dbutils 只是帮我们简化了CRUD 的代码, 但是连接的创建以及获取工作。 不在他的考虑范围
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
//增加
//queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000);
//删除
//queryRunner.update("delete from account where id = ?", 5);
//更新
//queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);
直接new接口的匿名实现类
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
Account account = queryRunner.query(“select * from account where id = ?”, new ResultSetHandler(){
@Override
public Account handle(ResultSet rs) throws SQLException {
Account account = new Account();
while(rs.next()){
String name = rs.getString("name");
int money = rs.getInt("money");
account.setName(name);
account.setMoney(money);
}
return account;
}
}, 6);
System.out.println(account.toString());
直接使用框架已经写好的实现类。
查询单个对象
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
//查询单个对象
Account account = queryRunner.query(“select * from account where id = ?”,
new BeanHandler(Account.class), 8);
查询多个对象
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
List list = queryRunner.query("select * from account ",
new BeanListHandler(Account.class));
###ResultSetHandler 常用的实现类
以下两个是使用频率最高的
BeanHandler, 查询到的单个数据封装成一个对象
BeanListHandler, 查询到的多个数据封装 成一个List<对象>
ArrayHandler, 查询到的单个数据封装成一个数组
ArrayListHandler, 查询到的多个数据封装成一个集合 ,集合里面的元素是数组。
MapHandler, 查询到的单个数据封装成一个map
MapListHandler,查询到的多个数据封装成一个集合 ,集合里面的元素是map。
ColumnListHandler
KeyedHandler
ScalarHandler
脏读, 不可重复度,幻读
丢失更新
悲观锁
乐观锁
读未提交
读已提交
可重复读
可串行化
不使用配置
使用配置
不使用配置
使用配置(必须掌握)
简化了CURD 。里面定义了通用的CURD 方法
queryRunner.updata();
queryRunner.query
装饰者模式