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.properties

#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.
  




原创粉丝点击