发表于: 2017-09-09 23:36:26
2 825
一、 今天完成的事情
1) 深度思考
Q18为什么要处理异常,Try/Catch应该在什么样的场景下使用,在真实的系统中,会出现网络中断,DB连接不上的错误吗?多久会发生一次?
① Java异常是指Java中将可预见的错误封装成对象。异常处理机制能有效预防错误的程序代码或系统错误造成的不可挽回的损失,提高了程序的健壮性,也方便了后期的开发维护。
② 对于try/catch的使用,一般说只在最外层函数上才需要。因为这里不能再外异常了,也就是说除非你有一种有价值的方式去处理异常,否则不要使用try/catch,只需要外抛异常就行了,在最后才处理它。
③ 服务器宕机时就会发生这种情况。一般是由操作员意向操作的重启服务器,或非意愿的重启,亦或是用户访问量超过空间限制等情况引起的down机。
Q19日志应该怎么打,在什么位置,需要打印出来什么样的关键参数?
① 打印日志的总体原则是清晰,易读。分多条信息分别输出,分日志级别,控制日志信息的条数,减少不重要的信息量。
② 在所有的输入输出处要输出日志;调用第三方软件要输出日志;对方系统处理时间要输出日志;关键控制点要输出日志。
③ 日志级别、时间、位置、信息
Q20为什么需要单步调试?Debug的时候IDE是怎么找到源码的?
① 对于一个代码量较大的项目报错却又无法直接通过错误信息解决时,使用单步调试可以透明化代码的每一步执行,方便开发者理清每一步骤发生了什么,从而排查出错误原因。
② 通过动态链接库。主要是通过实现jdwp的动态链接库,利用agentlib的机制在启动或运行器动态执行动态链接库。(这一原理设计太多复杂的东西,我也是找了很久的文档后勉强总结)
Q21可否远程连接到线上直接调试?真实的项目中,遇到问题的排查方案是什么?
① 可以,称为远程调试,本地的Java源码可以用socket连接到远端的JVM,进而执行调试
② 看日志,调试异常点
2) MyBatis
1) API
① Resources类,用于读取资源文件,在mybatis中读取主配置文件
② SqlSessionFactoryBuilder类,通过使用它的build方法创建SqlSessionFactory,完成后可被销毁
③ SqlSessionFactory接口对象是一个重量级对象,系统开销大,且是线程安全的,所有一个应用只需要一个该对象即可
④ SqlSession接口,用于执行持久化操作,一个SqlSession对应一次数据库会话,一次会话以SqlSession对象的创建开始,以Sql对象的关闭结束
⑤ 源码分析
分析之前回顾一个之前的代码,发现几个问题:
Resources读取主配置文件获取的inputStream流为什么没有手动关闭?
为什么插入操作后是sqlSesion.commit()提交会话,而不是提交事务?
为什么遇到异常不用回滚直接关闭会话?
首先阅读SqlSessionFactoryBuilder().build(InputStream inputStream)
发现传入的inputStream流在读取完主配置文件最后被关闭了,解决第一个问题
然后,阅读SqlSession.openSession()
进入DefaultSqlSessionFactory.openSession(),请记住最后一个参数,传入的是false
进入openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false)
注意到,刚刚最后一个参数的命名是autoCommit,即自动提交,而传入的是false,意味着不会自动提交,也就是说,打开的SqlSession不会自动提交,需要手动提交
看try中的内容,进入DefaultSqlSession(…)方法
从DefaultSqlSession(…)实现代码中,可以得出结论:创建数据库会话实际是对SqlSession进行初始化,其中dirty变量是一个标志,表示是否允许脏数据(脏数据意味着内容中数据和数据库中的数据不一致),这里需要记住此时创建的SqlSession不允许脏数据
接着,阅读相关操作的源码,这里我选择了insert方法
发现无论是insert、delete、update方法,最后都是调用同一个update方法。
此时,在update方法中可以看到,dirty被设为true了,也就说允许脏数据,毕竟插入数据时首先要更改内存中的数据,接着再更新到数据库中
看SqlSession.commit()
一进来,commit方法中调用了另一个commit,且传入了false
继续看下去,阅读commit方法中的isCommitOrRollbackRequired(boolean)方法
在isCommitOrRollbackRequired(boolean)方法中发现两个参数,autoCommit和dirty,此时autoCommit=false,dirty=true,表达式的结果为true,返回true
回到commit方法中,阅读BaseExecutor.commit(),我们知道传入的值为true。可以看到transaction.commit(),意味着事务被提交了,解决了第二个问题
同时记住,提交后dirty又被赋值为false
最后,阅读SqlSession.close()
又看见了isCommitOrRollbackRequired(boolean)方法,传入的值为false
dirty此时为false,force也为false,返回值为false
这样一次完整的数据库操作便完成了
可是,返回的false有什么用?回去阅读commit的源码,发现其参数名为forceRollBack,意思是强制回滚,当传入true的时候就会进行回滚。
那么什么时候传入true呢?这由isCommitOrRollbackRequired(boolean)方法返回值决定,
再看一次isCommitOrRollbackRequired(boolean)方法源码
发现传入的force一直是false,autoCommit默认也是false,因此返回值可以说是由dirty决定,当dirty为true时,返回值为true,需要进行事务回滚。
而dirty为true,意味着允许读脏数据,也就是说更新操作后没有正常提交事务,使dirty保持为true,数据写入不到数据库,所以需要进行回滚。这也就解释最后一个问题。
2) 完善总配置文件
① 新增properties标签,用于注册数据库连接的四要素属性
Jdbc_mysql.properties文件写入的是连接mysql数据库的四要素
此时,dataSource中property的value值就可不用写“死”
这也方便了以后更改为别的数据库时只需更改注册的properties文件即可,如改为jdbc_oracle.properties,jdbc_db2.properties等
② 新增typeAliases标签,定义类型别名
Name中填入的值为需要起别名的类的包名
这样以后,mapper.xml映射文件中的parameterType值可直接用类名,甚至不写,不用全限定名
二、 明天计划的事情
1)mybatis的学习
三、 遇到的问题
四、 收获
评论