事务
什么是事务? 转账: 1. 给张三账户减1000元 2. 给李四账户加1000元
当给张三账户减1000元后,抛出了异常!这会怎么样呢?我相信从此之后,张三再也不敢转账了。
使用事务就可以处理这一问题:把多个对数据库的操作绑定成一个事务,要么都成功,要么都失败!
==============
事物的特性:ACID
* 原子性:事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。 * 一致性:事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。 * 隔离性:隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。 * 持久性:一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
==============
MySQL操作事务
1. 开始事务:start transaction 2. 结束事务:commit或rollback
==============
JDBC事务
1. 开始事务:con.setAutoCommit(false); 2. 结束事务;con.commit()或con.rollback();
==============
保存点
保存点的是可以回滚到事务中的某个位置,而不是回滚整个事务。 回滚到保存点不会结束事务。 设置保存点:Savepoint sp = con.setSavepoint(); 回滚到保存点:con.rollback(sp);
==============
事务隔离级别
* 脏读:读到未提交 * 不可重复读:两次读取不一致,读取到另一事务修改的记录 * 幻读:两次读取不一致,读取到另一事务插入的记录
--------------
四大隔离级别 * SERIALIZABLE(串行化):对同一数据的访问是串行的,即非并发的,所以不会出现任何并发问题。易出现死锁,效率太低!不可用! * REPEATABLE READ(可重复读):防止了脏读、不可重复读,但没有防止幻读 * READ COMMITTED(读已提交):防止了脏读,但没有防止不可重复读,以及幻读 * READ UNCOMMITTED(读未提交):可能出现所有并发问题,效率最高,但不可用!
MySQL默认事务隔离级别为:REPEATABLE READ Oracle默认事务隔离级别为:READ COMMITTED
--------------
MySQL设置事务隔离级别 * 查看:select @@tx_isolation * 设置:set transaction isolation level 四选一
JDBC设置事务隔离级别 con.setTransactionIsolation(四选一)
===============
数据库连接池
作用:使用池来管理连接的生命周期,节省资源,提高性能。 java提供的连接池接口:javax.sql.DataSource,连接池厂商的连接池类需要实现这一接口。
-------------
DBCP
jar:commons-pool.jar、commons-dbcp.jar
BasicDataSource ds = new BasicDataSource(); ds.setUsername("root"); ds.setPassword("123"); ds.setUrl("jdbc:mysql://localhost:3306/mydb1"); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setMaxActive(20); ds.setMaxIdle(10); ds.setInitialSize(10) ; ds.setMinIdle(2) ; ds.setMaxWait(1000) ; Connection con = ds.getConnection();
-------------
C3P0
jar:c3p0-0.9.2-pre1.jar、c3p0-oracle-thin-extras-0.9.2-pre1.jar、mchange-commons-0.2.jar
ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb1"); ds.setUser("root"); ds.setPassword("123"); ds.setDriverClass("com.mysql.jdbc.Driver"); ds.setAcquireIncrement(5) ; ds.setInitialPoolSize(20) ; ds.setMinPoolSize(2) ; ds.setMaxPoolSize(50) ; Connection con = ds.getConnection();
-------------
C3P0配置文件
1. 通过默认配置初始化连接池 ComboPooledDataSource ds = new ComboPooledDataSource(); Connection con = ds.getConnection();
<default-config> <property name="xxx">XXX</property> </defualt-config>
2. 通过命名配置初始化连接池 ComboPooledDataSource ds = new ComboPooledDataSource("oracle-config"); Connection con = ds.getConnection();
<named-config name="orcale-config"> <property name="xxx">XXX</property> </named-config>
==================
Tomcat配置连接池 在server.xml中,或在conf/catalina/localhost/下创建xml文件
<Context> <Resource name="myc3p0" type="com.mchange.v2.c3p0.ComboPooledDataSource" factory="org.apache.naming.factory.BeanFactory" user="root" password="123" classDriver="com.mysql.jdbc.Driver" jdbcUrl="jdbc:mysql://127.0.0.1/mydb1" maxPoolSize="20" minPoolSize ="5" initialPoolSize="10" acquireIncrement="2"/> </Context>
-------------
获取Tomcat资源 Context cxt = new InitialContext(); DataSource ds = (DataSource)cxt.lookup("java:/comp/env/myc3p0"); Connection con = ds.getConnection();
==================
修改JdbcUtils
public class JdbcUtils { private static DataSource dataSource = new ComboPooledDataSource();
public static DataSource getDataSource() { return dataSource; }
public static Connection getConnection() { try { return dataSource.getConnection(); } catch (Exception e) { throw new RuntimeException(e); } } }
==================
DBUtils
jar:commons-dbutils.jar 核心类:QueryRunner、ResultSetHandler
QueryRunner方法: * update():DDL、DML * query():DQL * batch():批处理
-------------
增、删、改
public void fun1() throws SQLException { QueryRunner qr = new QueryRunner(); String sql = "insert into user values(?,?,?)"; qr.update(JdbcUtils.getConnection(), sql, "u1", "zhangSan", "123"); }
-------------
查
DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student";
// 把结果集转换成Bean Student stu = qr.query(sql, new BeanHandler<Student>(Student.class));
// 把结果集转换成Bean的List List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class));
// 把结果集转换成Map Map<String,Object> map = qr.query(sql, new MapHandler());
// 把结果集转换成List<Map> List<Map<String,Object>> list = qr.query(sql, new MapListHandler() );
// 把结果集转换成一列的List List<Object> list = qr.query(sql, new ColumnListHandler("name")) ;
// 把结果转换成单行单列的值 Number number = (Number)qr.query(sql, new ScalarHandler());
================
批处理
DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "insert into tab_student values(?,?,?,?)"; Object[][] params = new Object[10][]; //表示 要插入10行记录 for(int i = 0; i < params.length; i++) { params[i] = new Object[]{"S_300" + i, "name" + i, 30 + i, i%2==0?"男":"女"}; } qr.batch (sql, params);