Mybatis源码解读
来源:互联网 发布:英语文章带翻译软件 编辑:程序博客网 时间:2024/05/17 12:23
一:先看下面一个简单的mybatis的程序
package com.hanwei;import org.junit.Before;import com.hanwei.dao.Istudent;import com.hanwei.dao.impl.IstudentImpl;import com.hanwei.pojo.Student;public class Test {private Istudent student;private Student stu;@Beforepublic void before() {student = new IstudentImpl();stu = new Student();//test();}@org.junit.Testpublic void test() {stu.setGrade("一年级");stu.setName("2111");stu.setSex("男");stu.setAge("7");//插入一个对象student.insert(stu);student.insertgetUserIDcatche(stu);//插入一个变量student.insertoneparame("7");}/*public static void main(String args[]) {new Test().before();}*/}
package com.hanwei.dao;import com.hanwei.pojo.Student;public interface Istudent { public void insert(Student student);//插入}
package com.hanwei.dao.impl;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.hanwei.dao.Istudent;import com.hanwei.pojo.Student;public class IstudentImpl implements Istudent{@Overridepublic void insert(Student stu) {// TODO Auto-generated method stubSqlSession sqlSession=null;InputStream inputStream=null;try {//创建主配置文件inputStream = Resources.getResourceAsStream("mybatis.xml");//创建sqlSessionFactory对象 这里的build方法已经把inputStream关闭了,所以后面不需要再关闭一次SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);//创建sqlsession对象sqlSession=sqlSessionFactory.openSession();System.out.println(sqlSession);//sqlSession.insert("student", stu);sqlSession.insert("student", stu);//最终事务提交 sqlSession.commit();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally {/* * */ //事务关闭 事务提交后就不用回滚 否则回滚数据不会写到数据库if(sqlSession!=null) {sqlSession.close();}}}@Overridepublic void insertgetUserIDcatche(Student student) {//插入并且获取刚插入的id// TODO Auto-generated method stubSqlSession sqlSession=null;InputStream inputStream=null;try {//创建主配置文件inputStream = Resources.getResourceAsStream("mybatis.xml");//创建sqlSessionFactory对象 这里的build方法已经把inputStream关闭了,所以后面不需要再关闭一次SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);//创建sqlsession对象sqlSession=sqlSessionFactory.openSession();System.out.println(sqlSession);//sqlSession.insert("student", stu);System.out.println("插入前学生信息"+student.getId());sqlSession.insert("getUserinsertIDcatche", student);//最终事务提交 sqlSession.commit();System.out.println("插入后学生信息"+student.getId());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally {/* * */ //事务关闭 事务提交后就不用回滚 否则回滚数据不会写到数据库if(sqlSession!=null) {sqlSession.close();}}}@Overridepublic void insertoneparame(String studentage) {//只给谋列插入单个值// TODO Auto-generated method stub// TODO Auto-generated method stubSqlSession sqlSession=null;InputStream inputStream=null;try {//创建主配置文件inputStream = Resources.getResourceAsStream("mybatis.xml");//创建sqlSessionFactory对象 这里的build方法已经把inputStream关闭了,所以后面不需要再关闭一次SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);//创建sqlsession对象sqlSession=sqlSessionFactory.openSession();System.out.println(sqlSession);//sqlSession.insert("student", stu);//System.out.println("插入前学生信息"+student.getId());sqlSession.insert("student", studentage);//最终事务提交 sqlSession.commit();//System.out.println("插入后学生信息"+student.getId());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally {/* * */ //事务关闭 事务提交后就不用回滚 否则回滚数据不会写到数据库if(sqlSession!=null) {sqlSession.close();}}}}
mybatis.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><!-- ?代表只能小于等于1个 --><configuration> <!-- 引进数据库变量配置文件 --> <properties resource="jdbc.properties"/> <!-- 简化mapper文件中很长的实体类名位置parameterType alias别名--> <typeAliases> <typeAlias type="com.hanwei.pojo.Student" alias="xxx"/> </typeAliases> <!-- 可以来选择用什么数据库环境,本地还是服务器或者MySQL还是Oracle --> <environments default="mysqlEM"> <!-- 大于等于0个 --> <environment id="mysqlEM"> <!--jdbc默认的事务管理 --> <transactionManager type="JDBC"/> <!-- --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 注册映射文件 也可以url="指向硬盘物理路径"--> <mappers> <mapper resource="com/hanwei/dao/mapper/studentmapper.xml"/> </mappers> </configuration>
mapper.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="xxx"> <insert id="student" parameterType="xxx"> insert into T_student (name,age,grade,sex) values(#{name}, #{age},#{grade},#{sex}) </insert> <!--这里的#{}只是一个占位符 里面可以包含任何值--> <insert id="insertoneparame" parameterType="xxx"> insert into T_student (age) values(#{zzzzz}) </insert> <insert id="getUserinsertIDcatche" parameterType="xxx"> insert into T_student (name,age,grade,sex) values(#{name}, #{age},#{grade},#{sex}) <selectKey resultType="int" keyProperty="id" order="AFTER"> select @@identity </selectKey> </insert> </mapper>
#log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%-5p][%d{yyyy-MM-dd HH:mm:ss}] %c %L %m%n log4j.rootLogger=debug,stdout
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://127.0.0.1:3306/testjdbc.username=rootjdbc.password=123456
1.问题一发现IstudentImpl没有对inputstream输入流进行关闭
最终源码发现
//创建sqlSessionFactory对象 这里的build方法已经把inputStream关闭了,所以后面不需要再关闭一次
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
2.当我们去掉sqlSession.commit();会出现
[DEBUG][2017-10-24 14:23:41] com.hanwei.pojo.Student.student 49 <== Updates: 1
[DEBUG][2017-10-24 14:23:41] org.apache.ibatis.transaction.jdbc.JdbcTransaction 49 Rolling back JDBC Connection [com.mysql.jdbc.JDBC4Connection@731a74c]
[DEBUG][2017-10-24 14:23:41] org.apache.ibatis.transaction.jdbc.JdbcTransaction 49 Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@731a74c]
[DEBUG][2017-10-24 14:23:41] org.apache.ibatis.transaction.jdbc.JdbcTransaction 49 Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@731a74c]
[DEBUG][2017-10-24 14:23:41] org.apache.ibatis.datasource.pooled.PooledDataSource 49 Returned connection 120694604 to pool.
不难发现jdbc.JdbcTransaction 49 Rolling back JDBC Connection 事务回滚,再回到数据库查看发现没有数据插入????/
这是为什么呢?
追踪方法源码
sqlSession=sqlSessionFactory.openSession();
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
//autoCommit=false
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
return new DefaultSqlSession(configuration, executor);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//dirty=false
public DefaultSqlSession(Configuration configuration, Executor executor) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
}
sqlSession.insert("student", stu);
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
dirty = true;
(1)当我们关闭sqlSession.commit();
追踪方法close()
isCommitOrRollbackRequired(false)//返回true
public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
private boolean isCommitOrRollbackRequired(boolean force) {
return dirty || force;
}
forceRollback=true
public void close(boolean forceRollback) {
try {
try {
rollback(forceRollback);
} finally {
if (transaction != null) transaction.close();
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.debug("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}
//required=true
public void rollback(boolean required) throws SQLException {
if (!closed) {
try {
clearLocalCache();
flushStatements(true);
} finally {
if (required) {
transaction.rollback();
}
}
}
}
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
}
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
}
(2)当我们打开sqlSession.commit();
// dirty = true;
public void commit() {
commit(false);
}
public void commit(boolean force) {
try {
executor.commit(isCommitOrRollbackRequired(force));
dirty = false;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private boolean isCommitOrRollbackRequired(boolean force) {
return dirty || force;
}
public void commit(boolean required) throws SQLException {
if (closed) throw new ExecutorException("Cannot commit, transaction is already closed");
clearLocalCache();
flushStatements();
if (required) {
transaction.commit();//事务提交
}
}
//dirty = false;
public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
private boolean isCommitOrRollbackRequired(boolean force) {
return dirty || force; //false
}
forceRollback=true
public void close(boolean forceRollback) {//false
try {
try {
rollback(forceRollback);//false
} finally {
if (transaction != null) transaction.close();
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.debug("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}
public void rollback(boolean required) throws SQLException {//false
if (!closed) {
try {
clearLocalCache();
flushStatements(true);
} finally {
if (required) {//false 不会事务回滚
transaction.rollback();
}
}
}
}
这就解释了为什么打开屏蔽的提交代码会出现事务提交并且数据库有数据,但是自增长id不是加1变成了加2,并且也会提交事务。
[DEBUG][2017-10-24 14:41:33] com.hanwei.pojo.Student.student 49 <== Updates: 1
[DEBUG][2017-10-24 14:41:33] org.apache.ibatis.transaction.jdbc.JdbcTransaction 49 Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@731a74c]
[DEBUG][2017-10-24 14:41:33] org.apache.ibatis.transaction.jdbc.JdbcTransaction 49 Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@731a74c]
[DEBUG][2017-10-24 14:41:33] org.apache.ibatis.transaction.jdbc.JdbcTransaction 49 Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@731a74c]
[DEBUG][2017-10-24 14:41:33] org.apache.ibatis.datasource.pooled.PooledDataSource 49 Returned connection 120694604 to pool.
- Mybatis源码解读
- mybatis源码解读(1)
- mybatis源码解读(2)
- mybatis源码解读(3)
- mybatis源码解读(5)
- mybatis源码解读(6)
- mybatis源码解读(7)
- mybatis源码解读(8)
- mybatis之MapperFactoryBean源码解读
- MyBatis插件原理-源码解读
- MyBatis的Sql执行过程源码解读
- mybatis--源码解读---XML的解析
- Mybatis如何加载配置文件 源码解读parameterType
- mybatis源码中的设计模式解读
- Mybatis源码解读——Mybatis demo工作流程
- 源码解读Mybatis List列表In查询实现的注意事项
- 源码解读Mybatis List列表In查询实现的注意事项
- 源码解读Mybatis List列表In查询实现的注意事项
- 流式输入/输出原理
- ubuntu14.04 server python3 安装matplotlib失败及解决方法
- 收集的机器学习面试问题
- scrapy安装,Twisted报错处理
- 关于上传压缩文件解析
- Mybatis源码解读
- android、java获得代码执行时长
- RecyclerView使用notifyItemRemoved错乱
- 二维码、Logger日志、Butterknife
- js垃圾回收机制
- python生产者消费者模型
- 如何快速通过json构建javabean对象(Intellij IDEA-->GsonFormat使用教程)
- Java反射机制
- 虚拟网卡创建