第6章 数据库事务
1.数据库事务介绍
*事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态
*事务处理:保证所有事务都作为一个工作单元来执行
2.JDBC事务处理
*数据一旦提交则不可回滚
*导致数据自动提交的操作:DDL操作、DML默认情况、关闭连接时
3.事务的ACID属性
(1)ACID属性
原子性:事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态
隔离性:一个事务的执行不能被其他事务干扰
持久性:一个事务一旦被提交,它对数据库中数据的改变就是永久性的
(2)数据库的并发问题
脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的。
不可重复读:对于两个事务T1,T2,T1读取了一个字段,然后 T2 更新了该字段。之后, T1再次读取同一个字段,值就不同了。
幻读:对于两个事务T1, T2, T1从一个表中读取了一个字段, 然后T2在该表中插入了一些新的行。之后,如果T1再次读取同一个表,就会多出几行。
(3)四种隔离级别
*Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。
Oracle 默认的事务隔离级别为: READ COMMITED
*Mysql 支持 4 种事务隔离级别。
Mysql 默认的事务隔离级别为: REPEATABLE READ
(4)在MySQL中设置隔离级别
第7章 DAO及相关实现类
*BaseDAO:装针对于数据表的通用操作;使用abstract修饰,表示不能被实例化;针对不同的表提供具体的DAO
*xxDAO接口:用于规范针对某数据表的常用操作
*xxDAOImpl抽象类:继承BaseDAO,实现xxDAO接口
BaseDAO:
package chapter7;
import utils.JDBCUtiles;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
/*封装针对于数据表的通用操作*/
/*使用abstract修饰,表示不能被实例化*/
/*针对不同的表提供具体的DAO*/
public abstract class BaseDAO<T> {
private Class<T> clazz=null;
{
//获取当前子类的泛型
Type genericSuperclass = this.getClass().getGenericSuperclass();
ParameterizedType paramType= (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = paramType.getActualTypeArguments();
clazz=(Class<T>) actualTypeArguments[0];
}
//通用的查询操作,用于返回查询结果集(考虑事务)
public ArrayList<T> getInstance(Connection conn, String sql, Object ...args){
ArrayList<T> ts = null;
PreparedStatement pr = null;
ResultSet resultSet = null;
try {
ts = new ArrayList<>();
pr = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
pr.setObject(i+1,args[i]);
}
resultSet = pr.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
while (resultSet.next()){
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
Object value = resultSet.getObject(i + 1);
String name = metaData.getColumnLabel(i + 1);
Field declaredField = clazz.getDeclaredField(name);
declaredField.setAccessible(true);
declaredField.set(t,value);
}
ts.add(t);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtiles.closeResource(null,pr,resultSet);
}
return ts;
}
//通用的增删改操作,获取连接和关闭连接都在外部进行
public int update(Connection conn,String sql,Object... args){
PreparedStatement pr=null;
try {
pr = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
pr.setObject(i+1,args[i]);
}
return pr.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtiles.closeResource(null,pr);
}
return 0;
}
//用于查询特殊值的通用方法
public <E> E getValue(Connection conn,String sql,Object... args){
PreparedStatement pr = null;
ResultSet resultSet = null;
try {
pr = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
pr.setObject(i+1,args[i]);
}
resultSet = pr.executeQuery();
if(resultSet.next()){
return (E)resultSet.getObject(1);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtiles.closeResource(null,pr,resultSet);
}
return null;
}
}
xxDAO接口
package chapter7;
import bean.Customer;
import java.sql.Connection;
import java.util.Date;
import java.util.List;
/*此接口用于规范针对于customers表的常用操作*/
public interface CustomerDAO {
//将cust对象添加到数据库中
void insert(Connection conn, Customer cust);
//根据指定的ID删除表中的一条记录
void deleteByID(Connection conn,int id);
//根据指定的ID修改数据表中的记录
void updateByID(Connection conn,int id,Customer cust);
//根据指定的ID查询对应的Customer对象
Customer getCustomerByID(Connection conn,int id);
//查询表中的所有记录构成的集合
List<Customer> getAll(Connection conn);
//返回数据表中数据的条目数
Long getCount(Connection conn);
//返回数据表中最大的生日
Date getMaxBirth(Connection conn);
}
xxDAOImpl抽象类:
package chapter7;
import bean.Customer;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO{
//将cust对象添加到数据库中
@Override
public void insert(Connection conn, Customer cust) {
String sql="insert into customers(name,email,birth) values(?,?,?)";
update(conn,sql,cust.getName(),cust.getEmail(),cust.getBirth());
}
//根据指定的ID删除表中的一条记录
@Override
public void deleteByID(Connection conn, int id) {
String sql="delete from customers where id=?";
update(conn,sql,id);
}
//根据指定的ID修改数据表中的记录
@Override
public void updateByID(Connection conn, int id, Customer cust) {
String sql="update customers set name=?,email=?,birth=? where id=? ";
update(conn,sql,cust.getName(),cust.getEmail(),cust.getBirth(),id);
}
//根据指定的ID查询对应的Customer对象
@Override
public Customer getCustomerByID(Connection conn, int id) {
String sql="select name,email,birth from customers where id=?";
ArrayList<Customer> instance = getInstance(conn, sql, id);
return instance.get(0);
}
//查询表中的所有记录构成的集合
@Override
public List<Customer> getAll(Connection conn) {
String sql="select name,email,birth from customers ";
ArrayList<Customer> instance = getInstance(conn, sql);
return instance;
}
//返回数据表中数据的条目数
@Override
public Long getCount(Connection conn) {
String sql="select count(1) from customers";
Object value = getValue(conn, sql);
return (Long) value;
}
//返回数据表中最大的生日
@Override
public Date getMaxBirth(Connection conn) {
String sql="select max(birth) from customers";
Object value = getValue(conn, sql);
return (Date) value;
}
}