从零开始学后端(4)——JDBC的重构设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012124438/article/details/81432143

重构(Refactoring)就是通过调整程序代码,改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。

问题1:每个DAO方法中都会写:驱动名称/url/账号/密码,不利于维护.
这里写图片描述

如果现在我们从MySQL迁移到Oracle中去,此时就得修改每一个DAO方法的驱动名称/url/账号/密码.
解决方案:使用成员变量来表示,成员变量的作用域在整个类中有效.
这里写图片描述

这里写图片描述

问题1已经解决(通过在DAO类中定义成员变量).
问题2:我们在开放中会存在N个DAO实现类,那么此时每一个DAO实现类中都得提供连接数据库的四个基本要素的成员变量.

解决方案:现在需要完成在多个类中共享驱动名称/url/账号/密码四个信息,我们可以定义一个类(JdbcUtil),把这四个信息存储在该类中,并且使用public static修饰.

这里写图片描述

此时DAO代码:
这里写图片描述

问题3: 问题2是完美解决了,但是存在一些遗憾:
1):JdbcUtil中的四个字段应该私有化起来,体现封装.
2):其实在DAO实现类中,仅仅需要获取一个Connection对象即可,至于该对象如何创建,可以不关心.

解决方案:我们在JdbcUtil类中提供一个静态方法,用于返回Connection对象.

这里写图片描述

扫描二维码关注公众号,回复: 3834602 查看本文章

此时DAO代码:
conn = JdbcUtil.getConn();

问题4:我们分析右图JdbcUtil类中的getConn方法的代码,发现,每次调用getConn方法都需要加载注册驱动,而我们其实就只需要在最初加载一次即可.

解决方案:在静态代码块中去加载和注册数据库驱动即可.

这里写图片描述

问题5:每一个DAO方法最后,都需要释放资源,该代码没有技术含量,又臭又长.

DML操作: 关闭Connection和Statement对象.
DQL操作: 关闭Connection和Statement以及ResultSet对象.

解决方案:在JdbcUtil类中提供close方法用于关闭三个资源对象.
这里写图片描述

关闭DML操作资源:JdbcUtil.close(conn,st,null);
关闭DQL操作资源: JdbcUtil.close(conn,st,rs);

问题6:在JdbcUtil类中提供了四个字段分别表示连接数据库的四要素(驱动类名,URL,账号,密码),存在硬编码,如果需要修改连接的数据库,就只能来修改该源代码.
这里写图片描述

解决方案: 我们一般把数据库的连接信息存放到属性文件中(db.properties).

这里写图片描述

接下来再通过Properties类来加载资源文件,并读取其中的信息即可.

这里写图片描述

这里写图片描述

问题7:在DAO方法中拼接SQL语句,很恶心,稍后使用PreparedStatement解决.
问题8:在每一个DAO方法中都创建一个新的Connection对象,使用之后,就立刻释放了,也就是说没有充分利用Connection对象,而创建Connection对象的成本非常大,
问题9:DML操作模板是相同的,DQL操作模板也是相同的.

预编译语句对象

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

预编译语句对象 VS 静态语句对象

Statement和PreparedStatement的区别:
PreparedStatement 的优点:
1).PreparedStatement 代码的可读性和可维护性. (SQL模板,使用占位符表示参数)
2).PreparedStatement 能最大可能提高性能(预编译),MySQL不支持PreparedStatement的性能优化.
3).PreparedStatement 能保证安全性.
可以防止SQL注入:演示登陆操作
选择:使用PreparedStatement.

这里写图片描述

这里写图片描述

这里写图片描述

事务管理操作

案例:银行转账:从张无忌账户上给赵敏转1000块.

准备:account(账户表):

id name(账号,唯一) balance(余额)
1 张无忌 20000

2 赵敏 0

操作步骤:
1):检查张无忌的账户余额是否大于等于1000.
SELECT * FROM account WHERE name = ‘张无忌’ AND balance >= 1000;
2):从张无忌的账户余额中减少1000.
UPDATE account SET balance = balance - 1000 WHERE name = ‘张无忌’;
3):再在赵敏的账户余额中增加1000.
UPDATE account SET balance = balance + 1000 WHERE name = ’ 赵敏’;

如果:在第二步和第三步之间如果程序中断,怎么办? 通过异常来模拟.

这里写图片描述

事务(Transaction,简写为tx):
     在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。
     我们把多个密不可分的操作看做是一个整体,那么该整体就称之为一个事务.
--------------------------------------------------
事务的ACID属性:
1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 
2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态,但是不最终数据不能被破坏,两个账户的总余额是不能改变的.
3. 隔离性(Isolation):MySQL再讲
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
--------------------------------------------------
事务:指构成单个逻辑工作单元的操作集合
事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态
处理事务的两个动作:
       提交:commit:   当整个事务中,所有的逻辑单元都正常执行成功.  ---->提交事务.---数据已经提交,不能更改.
       回滚:rollback:  当整个事务中,有一个逻辑单元执行失败,              ---->回滚事务.  
                      撤销该事务中的所有操作,释放锁--->恢复到最初的状态.
1):默认情况下,在JDBC中执行DML操作就会自动提交事务,此时我们得设置事务的手动提交机制(取消事务的自动提交).
2):查询操作,不涉及数据的更改,所以不需要事务.
3):MySQL中InnoDB存储引擎支持事务,MyISAM不支持.
     alter table account engine = 'MyISAM';

意识:如果是DML操作时,没有异常,代码也正确,但是数据改变不了,首先去想到事务没有提交.

操作事务的模板:

try{
   //取消事务自动提交:
   connection对象.setAutoCommit(false);
   操作1
   操作2
   操作3     
   //提交事务
   Connection对象.commit();
}catch(Exception e){
     //处理异常
     //回滚事务
    Connection对象.rollback();
}finally{
    释放资源
}

这里写图片描述

批处理操作

批量操作(batch):当需要成批插入或者更新记录时。
可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率.

JDBC的批量处理语句包括下面两个方法:
addBatch(String sql):添加需要批量处理的SQL语句或是参数;
executeBatch();执行批量处理语句;

通常我们会遇到两种批量执行SQL语句的情况:
多条SQL语句的批量处理; :Statement
一个SQL语句的批量传参; :PreparedStatement


需求:同时向t_student表,插入5000条数据.
   在JDBC中,MySQL不支持批量操作.
-------------------------------------------------------------------------
Statement 批处理 : 一次性可以执行多条sql语句,需要编译多次。
应用场景:系统初始化 (创建表,创建数据等)
添加sql语句,st.addBatch(sql)   --添加sql语句
批量处理sql语句,int[] st.executeBatch()
清除缓存: st.clearBatch();
-------------------------------------------------------------------------
PreparedStatement 批处理 : 执行一条sql语句,编译一次,执行sql语句的参数不同。
应用场景:表数据初始化
添加批量参数:psmt.addBatch()    --添加实际参数,执行之前,需要执行psmt.setXxx()设置实际参数
执行批处理:int[] psmt.executeBatch()
清除缓存:pstm.clearBatch();

猜你喜欢

转载自blog.csdn.net/u012124438/article/details/81432143
今日推荐