事务
- 事务的概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功;
例如:A----B转帐,对应用如下两条sql语句
update account set money=money-1000 where name=‘aaa’;
update account set money=money+1000 where name=‘bbb’;
- 数据库开启事务命令
shatrt transaction或begin 开启事务
Rollback 回滚事务
Commit 提交事务
- JDBC操作事务
- 事务的特性
原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生.
一致性:事务必须使数据库从一个一致性状态,换到另一个一致性状态,转帐前和转帐后总金额都不变。
隔离性:事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其它事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性:指一个事务一旦被提交,它对数据库中的数据改变就是持久性的,接下来,就算数据库有什么故障也不应该对其有任何影响。
- 事务的隔离级别
赃读:指一个事务读取到另一个事务没有提交的事务
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同,一个事务读取到了另一个事务提交后的数据,(Update)
虚读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致(insert)
数据库通过设置事务的隔离级别防止以上情况的发生:
1、READ UNCOMMITTED:赃读,不可重复读,虚读都有可能发生
2、READ COMMITTED:避免赃读。不可重复读和虚读有可能发生(Oracle)
4、REPEATABLE READ:避免赃读,不可重复读。虚读有可能发生(mysql)
8、SERIALIZABLE:避免赃读、不可重复读、虚读。
级别越高、性能越低、数据更安全
mysql中
查看当前事务的隔离级别:SELECT @@TX_ISOLATION;
更改当前的事务隔离级别:SET TRANSACTION ISOLATIONLEVEL 四个级别之一
设置隔离级别必须在事务之前
- JDBC控制事务的隔离级别
Connction中有五个常量
设置隔离级别:必须在开启事务之前
Connection.setTransactionIsolation(int level);
连接池
- 什么是数据库连接池?
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新再创建一个 ;释放空闲时间超过最大空闲时间的数据库连接起来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能
目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能
- 模拟连接池
- 编写标准的数据源(连接池)(装饰设计模式)
自定义数据库池连接池要实现javax.sql.DataSource接口
由于DataSource中没有close()方法
所以我们自己写一个类实现接口Connection重写close(),并通过构造把连接和连接池传进去
如下代码
实现java规定的连接池标准
实现Connection并重写close()
使用连接池创建连接Test
- 适配器实现连接池
常用的数据源配置
- DBCP
apache推出的Database Connection pool (数据库连接池)
使用步骤:
1、添加jar包
2、添加属性资源文件
3、编写工具类
4、使用工具类
1、添加jar包如下图
2、添加属性资源文件
3、编写工具类
4、使用工具类
- C3P0
使用步骤
1、添加jar包
2、编写配置文件
3、编写工具类
4、使用工具类
1、添加jar包
2、编写配置文件
3、编写工具类
4、使用工具类
DBUtils
- 什么是DBUtils,它的作用?
DBUtils是java编程中的数据库操作实用工具。小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作。可以少写代码
1、对于数据表的读操作,他可以把结果转换成List,Array,Set等Java集合,便于程序员操作;
2、对于数据表的写操作,也变得很简单。(只需要写sql语句)
3、可以使用数据源,使用JNDI,数据库连接池等技术来优化性能,重用已经构建好的数据库连接对象。
- DBUtils的三个核心对象
QueryRunner类 :提拱了对sql语句操作的API
主要有三个方法:
1、query();用于执行select语句
2、update();用于执行update、insert、delete
3、batch();批处理ResultSetHandler接口 (结果集)
用于定义select操作后,怎样封装结果集
DBUtils
它就是一个工具类,定义了关闭资源与事务处理的方法
- 快速入门
1、导入jar包
2、创建QueryRunner对象
3、使用query方法执行select语句
4、使用ResultSetHandler封装结果集
5、使用DButils类释放资源
分两种方法实现一个查询的操作
1
2
- QueryRunner对象
1、构造函数:new QueryRunner();它可以手动创建事务
也就是说此对象调用的方法(如:query、update、batrch)参数中要有Connection对象
new QueryRunner(DataSource ds);它的事务是自动控制的,一个sql一个事务
此对象调用的方法(如:query、update、batrch)参数中无需Connection对象
测试CRUD+批处理
public class TestCRUD {
//增
@Test
public void testInsert() {
QueryRunner or = new QueryRunner(C3P0Utils.getDataSource());
try {
int index = or.update("insert into user values(null,?,?,?)","成龙", 30, "男");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//删
@Test
public void testDelete() {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
try {
qr.update("delete from user where id=?", 7);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//查
@Test
public void testSelect() {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
try {
List<User> list = qr.query("select * from user", new BeanListHandler<User>(User.class));
for(User user : list) {
System.out.println(user);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//改
@Test
public void testUpdate() {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
try {
qr.update("update user set age=? where username=?", 37,"成龙");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//批处理,只能执行相同的sql语句
@Test
public void testBatch() {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
Object arr[][] = {
{"张静", 17, "女"},
{"张蔓", 12, "女"}
};
try {
qr.batch("insert into user values(null,?,?,?)", arr);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- ResultSetHandler的9个处理器
1、ArrayHandler:适合取一条记录,把该条记录的每列值封装到一个Object[]中
2、ArrayListHandler:适合取多条记录,把每一条记录的每列值封装到一个Object数组中,再把数组封装到一个list集合中.
3、ColumnListHandler:取某一列的值并封装到一个List集合中
4、KeyedHandler:取多条记录,把每一条记录封装到一个Map集合中,再把这个map封装到另一个map中,key为指定的字段值
5、MapHandler:适合取一条记录,把当前记录的列名和列值放到一个Map中
6、MapListHandler:适合取多条记录。把每条记录的列名和列值封装到一个map中,再把这个map封装到一个list中
7、ScalarHandler:适合取单行单列数据
8、BeanHandler
9、BeanListHandler
ThreadLocal
- 模拟ThreadLocal的设计,让大家明白他的作用.
public class ThreadLocal {
private Map<Runnable, Object> container = new Map<Runnble, Object>();
public void set(Object value) {
container.put(Thread.currentThread(), value); //用当前线程作为key
}
public Object get() {
return container.get(Thread.currentThread());
}
public void remove() {
container.remove(Thread.currentThread());
}
}
总结:调用该类的get方法,返回的都是当前线程放入的数据,线程局部变量