Day40
*对执行DQL的方法进行封装
I. 连接,设置参数等方式跟封装DML是一样的,但是DQL返回的是一个结果集,所以需要对这个结果集进行处理。那么怎么处理呢?自然是封装到一个集合当中进行返回。首先,我们肯定是需要自定义一个实体类来保存这些信息(实体类的属性名必须保证和sql语句的字段别名一致),那么我就等于是知道了这个集合的类型,如果要将类型告知给方法,那么自然是要使用Class对象作为参数传入,而且类型和返回的集合类型一致,这样我们就可以使用泛型来进行一个限制。
public static <T> List<T> executeDQL(Class<T> cls , String sql,Object...params){}
II. 参数,返回值定好了之后,自然是要进行逻辑代码的实现,也就是将结果集保存到list集合中
//·连接代码略,ps是预处理对象,rs是结果集
//·保存实体类对象的集合
List<T> list = new ArrayList<T>();
//·获取查询结果的元数据
ResultSetMetaData rm = ps.getMetaData();
T t;
while(rs.next()) {
//·获取一个实体类对象
t = cls.newInstance();
//·getColumnCount()可以获取到有多少个字段
for (int i = 1; i <= rm.getColumnCount(); i++) {
//·通过元数据获取字段的别名
String name = rm.getColumnLabel(i);
//·通过反射、属性名获取到这个对象的属性
Field field = cls.getDeclaredField(name);
//·打开权限(因为是私有属性)
field.setAccessible(true);
//·通过别名获取结果集的数据
Object value = rs.getObject(name);
//·对实体类的对象的属性进行复制
field.set(t, value);
}
//·将实体类添加进集合
list.add(t);
}
return list;
III. 优化:这样写是有两个小bug的,①实体类里面肯定不会存在外键,但是数据库的查询结果集可能存在外键;②如果数据库里的数据不完整(比如有空值,且恰好是数字类型的值为null),则在对实体类属性的赋值上会有一定的问题(数字类型没法赋值为null)。
1)使用try catch 处理第一个bug,抓住异常不做处理,因为对于实体类来说外键是废数据,可以直接忽略
try {
//·这里可能会出现异常:实体类里面没有数据库的外键
Field field = cls.getDeclaredField(name);
field.setAccessible(true);
Object value = rs.getObject(name);
field.set(t, value);
} catch (NoSuchFieldException e) {
}
2)加一个空值判断解决第二个bug,这里使用了continue直接跳过赋值,因为如果不赋值,那么成员会自动使用默认值,而数据库中的null在没有设置默认值的情况下也恰好代表这个意思。
Object value = rs.getObject(name);
//·如果是数字类型为空,直接赋值会有问题
if(value == null) {
continue;
}
field.set(t, value);
至此,一个基础版的DQL封装就完成了
*基于BaseDao开发和项目包结构
*面向接口开发
*事务
I. 概念:保证一组sql语句能够同时成功或者同时失败,且不会被其它事务所影响。
II. 事务的ACID:
Atomicity(原子性)表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
Consistency(一致性)表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态.事务执行前和执行后来源和去向保持平衡。
Isolation(隔离性)事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。并发时每个事务是隔离的,相互不影响。
Durability(持久性)持久性事务完成之后,它对于系统的影响是永久性的。
III. java代码中实现事务
try{
Connection.setAutoCommit(false);//·关闭了自动提交事务
//·加入几条sql语句
Connection.commit();//所有sql语句正常执行完毕 则提交
}catch(Exception e){
System.out.println("发生了异常");
Connection.rollback();//·如果发生异常就进行回归
}
IV. 事务的隔离级别
1)read uncommitted 未提交读(可能会发生脏读,不可重复读,虚读)
2)read committed 提交读(可能会发生不可重复读,虚读)
3)repeatable 重复读(可能会发生虚读)
4)Serializable 可串行化(都避免了,但是资源消耗很大)
V. 脏读,不可重复读,可重复读,虚读
1)脏读:事务1修改了一个值,但是还未提交;此时事务2对这个数据进行读取,读取到了修改后的值。
2)不可重复读:事务1第一次查询了一个数据发现是200,在事务1还没提交时,事务2将这个数据修改成了100并提交,事务1又查询了一次,发现值变成了100.
3)可重复读:与上面的情况相同,但是事务1又查询时,值还是200,直到事务1提交之后,重新开了一个事务3再查询时,值才会变成100.
4)虚读:与上面情况相同,但是事务2不再是修改数据,而是添加了一条新数据,当事务1又查询一次时,发现多了一条新数据.
的情况相同,但是事务1又查询时,值还是200,直到事务1提交之后,重新开了一个事务3再查询时,值才会变成100.
4)虚读:与上面情况相同,但是事务2不再是修改数据,而是添加了一条新数据,当事务1又查询一次时,发现多了一条新数据.