Mybatis 基本操作1

本文介绍了Mybatis的基本操作,包括框架简介、入门配置、核心类解析以及Mybatis配置文件的相关设置。Mybatis是一个简化JDBC过程的数据持久化框架,通过SqlSessionFactoryBuilder创建SqlSessionFactory,再由SqlSession执行SQL命令。文章详细讲解了SqlSession、SqlSessionFactoryBuilder、SqlSessionFactory等核心类的作用,并给出了配置文件中的重要元素,如<settings>、<typeAliases>、<typeHandlers>、<objectFactory>等的用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.简介

2.入门

2.1基本配置

2.2核心类

2.3案例

3.Mybatis配置文件-相关配置


1.简介

Mybatis 是一款数据持久化框架, 内部封装了 JDBC,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,并且也增加了一些高级特性,可以替代JDBC。一般只需要关注 SQL 语句本身, 想要使用Mybatis框架,导入mybatis-x.x.x.jar 和 mysql-connector-java-x.x.x.jar包就可以

Java JDBC

2.入门

2.1基本配置

该配置文件包含对Mybatis应用的核心配置, 包括获取数据库连接实例的数据源DataSource, 以及决定事务作用域和控制方式的事务管理器(TransactionManager), 简单示例:

<?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">
<configuration>
    <!-- 后面说明 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!-- mappers标签用于注册绑定我们的Mapper映射文件,告诉 MyBatis 到哪里去找到这些SQL语句,下面三种方式根据个人选择 -->
    <mappers>

        <!-- 通过类路径下资源引用,绑定Mapper映射文件,如果提示没找到,可以在out输出目录看一下是否存在 -->
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
        <!-- 任意位置Mapper映射文件,前面file:///固定写法,表示协议 -->      
        <mapper url="file:///C:\Users\eaeyon\Desktop\DogMapper.xml" />
        <!-- 直接使用映射接口的完全限定类名,但是其对应的Mapper映射文件需要在同包下,并且名字一样 -->
        <mapper class="dao.DogDao" />

    </mappers>
</configuration>

该配置文件是Mapper的映射配置文件

<?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="dao.DogDao">

    <select id="queryOne" resultType="dao.Dog">
        select * from Dog where id = #{id}
    </select>

</mapper>

2.2核心类

每个基于Mybatis的应用都是以一个SqlSessionFactory实例为核心,SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder对象创建

1.SqlSessionFactoryBuilder:

用于创建SqlSessionFactory,有很多重载方法 , 传入的参数就是mybatis的配置文件, 创建完成后SqlSessionFactoryBuilder就不使用了

a.通过mybatis.xml配置文件创建

InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

b.通过Configuration配置类创建

//数据源
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
//事务管理器
TransactionFactory transactionFactory = new JdbcTransactionFactory();
//环境
Environment environment = new Environment("development", transactionFactory, dataSource);
//配置类
Configuration configuration = new Configuration(environment);
//BlogMapper接口中包含SQL映射注解, 从而避免依赖xml文件
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

2.SqlSessionFactory:

用于创建SqlSession, 有很多重载方法 , 选择自己合适的就可以 , 一般Mybatis应用中创建一个SqlSessionFactory 实例就可以了,并且一直存在, 可以使用单例模式或者静态单例模式

public class Main {

    public static void main(String[] args) throws Exception{

        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session1 = sqlSessionFactory.openSession();
        System.out.println(session1); //org.apache.ibatis.session.defaults.DefaultSqlSession@27f674d


        SqlSession session2 = sqlSessionFactory.openSession();
        System.out.println(session2); //org.apache.ibatis.session.defaults.DefaultSqlSession@1d251891


    }
}

3.SqlSession:

SqlSession提供在数据库执行SQL命令的所有方法, 每个线程都应该有它自己的 SqlSession 实例,因此它的最佳的作用域是请求或方法作用域, 并且记得关闭

SqlSession也提供了javax.sql.Connection中相关方法 , 但实际执行的是它里面的Executor接口对象 , 而Executor中实际执行的是org.apache.ibatis.transaction.Transaction

所以SqlSession进行事务管理使用的是Transaction接口实现类 , SqlSession的getConnection()方法获取的Connection也是间接从Transaction接口实现类中获取 , 其实现类通过javax.sql.DataSource获取, 如果DataSource实现类使用了连接池技术, 就从池中获取

                

4.映射器实例:

映射器接口的实例从 SqlSession 中获得

2.3案例

        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //获取SqlSession
        try (SqlSession session = sqlSessionFactory.openSession()) {
            //获取映射器实例,调用方法执行SQL语句----推荐
            DogDao dogDao = session.getMapper(DogDao.class);
            Dog dog = dogDao.queryOne(1007);

            //直接调用SqlSession中方法 执行SQL语句----不推荐
            Dog dog1 = session.selectOne("dao.DogDao.queryOne", 1008);
            System.out.println(dog);
        }

3.Mybatis配置文件-相关配置

<properties> 引入外部配置文件,通过${}表达式使用

user=root
password=123456
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver
<configuration>

    <properties resource="jdbc.properties" >
         <!-- 启用默认值特性 -->
         <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> 
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driverClass}"/>
                <property name="url" value="${url}"/>

                <!-- 从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值 -->
                <!-- 用户名不对报错: Cause: java.sql.SQLException: Access denied for user '${myname}'@'localhost' (using password: YES) -->
                <!-- 配置文件中没有myname对应属性,可以设置默认值 -->
                <!-- <property name="username" value="${myname}"/> -->

                <property name="username" value="${myname:root}"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

<settings>极为重要的调整设置

<configuration>
    
    <settings>
        <!-- 开启或关闭全局已配置的缓存,默认true -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 延迟加载的全局开关,默认false -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="multipleResultSetsEnabled" value="true"/>
        
        .........
       
    </settings>

</configuration>

<typeAliases>类型别名

<typeAliases>

  <!-- Author可以用在任何使用 com.baidu.Author 的地方 -->
  <typeAlias alias="Author" type="com.baidu.Author"/>

  <!-- 也可以指定一个包, 将包中所有Java Bean的类名首字母小写作为别名-->
  <package name="com.baidu"/>
</typeAliases>

在Mybatis中,也有一些Java类型内建的类型别名,如

byte---->_byte                         Byte---->byte

int---->_int或者_integer          Integer---->int或者integer

<typeHandlers>类型处理器

类型处理器用于PreparedStatement中参数设置或者从结果集ResultSet中取出一个值时转换为对应java类型

public interface TypeHandler<T> {
    //设置PreparedStatement的占位符参数, 不同的类型处理器调用PreparedStatement的不同类型的设置方法
    //index表示要设置的位置 , param表示要设置的参数
    void setParameter(PreparedStatement ps, int index, T param, JdbcType var4) throws SQLException;

    //下面是将从ResultSet结果集中获取的值,转换为对应java类型,
    T getResult(ResultSet rs, String columnName) throws SQLException;

    T getResult(ResultSet rs, int columnIndex) throws SQLException;

    T getResult(CallableStatement var1, int var2) throws SQLException;
}

 分析IntegerTypeHandler

SQL语句:

<select id="queryOne" resultType="com.company.entity.Dog">
        select * from Dog where id = #{id} and name = #{name}
</select>
 Dog dog = dogDao.queryOne(1022,"cc");

第一个参数int类型, 经过一系列判断, 最后选择了IntegerTypeHandler , 然后执行他的 setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType);

public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            if (jdbcType == null) {
                throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
            }

            try {
                ps.setNull(i, jdbcType.TYPE_CODE);
            } catch (SQLException var7) {
                throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: " + var7, var7);
            }
        } else {
            try {
                //因为此时传的参数不为空,所以通过这个方法来设置
                this.setNonNullParameter(ps, i, parameter, jdbcType); 
            } catch (Exception var6) {
                throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different configuration property. Cause: " + var6, var6);
            }
        }

    }
  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setInt(i, parameter);
  }

所以PreparedStatement设置int类型参数时使用的是IntegerTypeHandler ; 第二个参数选择的是StringTypeHandler , 执行流程都是差不多的

因为上面是查询,结果会封装为Dog对象,所以会调用IntegerTypeHandler 和 StringTypeHandler中的getResult(ResultSet rs,Strng columnName)进行转换;

  @Override
  public T getResult(ResultSet rs, String columnName) throws SQLException {
    T result;
    try {
       //第一列: 实际getNullableResult()方法里面调用的是rs.getInt(columnName); columnName="id"
       //第一列: 实际getNullableResult()方法里面调用的是rs.getString(columnName); columnName="name"
      result = getNullableResult(rs, columnName);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
    }
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

自定义类型处理器,实现TypeHandler接口,或者继承BaseTypeHandler<T>类 , 泛型表示要处理的java类型,将她正确设置到PreparedStatement占位符,以及将从结果集获取的数据转换为该类型

//@MappedTypes(String.class)
//@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i,parameter);
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}
<typeHandlers>
  <!-- 添加自定义的类型处理器 -->
  <typeHandler handler="org.mybatis.example.MyTypeHandler"/>
</typeHandlers>

注意:

指定管理的Java类型: 

        1.BaseTypeHandler<T>指定泛型

        2.typeHandler元素设置javaType="String"

        3.类上添加@MappedTypes(String.class)注解指定

指定管理的JDBC类型:

        1.typeHandler元素设置jdbcType="VARCHAR"

        2.类上添加@MappedJdbcTypes(JdbcType.VARCHAR)注解指定

再次执行时,PreparedStatement设置String类型占位符时,就会选择MyTypeHandler

<objectFactory>对象工厂

public interface ObjectFactory {

  /**
   * Sets configuration properties.
   * @param properties configuration properties
   */
  void setProperties(Properties properties);

  /**
   * 用默认构造器创建对象
   */
  <T> T create(Class<T> type);

  /**
   * 用指定构造器创建对象 , 传入对应参数
   */
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  
  <T> boolean isCollection(Class<T> type);

}

 

每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作, 我们可以通过继承DefaultObjectFactory类创建自定义的对象工厂:

public class MyObjectFactory extends DefaultObjectFactory {

    //处理无参构造方法
    @Override
    public Object create(Class type) {
        System.out.println("无参构造Class Type : "+type);
        return super.create(type);
    }

    //处理带参数构造方法
    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        System.out.println("有参构造Class Type : "+type);
        System.out.println("ParamType List : "+type);
        System.out.println("ParamValue List : "+type);
        return super.create(type, constructorArgTypes, constructorArgs);
    }

    //用于配置ObjectFactory,mybatis.xml中其定义的属性会传递给该方法
    @Override
    public void setProperties(Properties properties) {
        System.out.println("获取属性: "+properties);
    }
}
 <objectFactory type="com.company.config.MyObjectFactory">
        <property name="name" value="zhangsan"/>
        <property name="age" value="12"/>
 </objectFactory>

执行结果:

 

<plugins>插件 允许你在映射语句执行过程中的某一点进行拦截调用,暂时了解

<environments>元素定义了如何配置环境 重要!!!

可以配置多个环境,但是每个SqlSessionFactory实例只能选择一种环境,比如需要连接两个数据库,就需要创建两个SqlSessionFactory实例

需要指定哪种环境,可以将他作为参数传递给SqlSessionFactoryBuilder

<environments default="development">
  <!-- 定义环境的id,默认使用的环境id default="development" -->
  <environment id="development">

    <!-- 事务管理器的配置: 即之前提到的Transaction接口 -->
    <transactionManager type="JDBC">
      <!-- 设置属性,会被传入他的setProperties(Properties)方法,和ObjectFactory类似 -->
      <property name="..." value="..."/>
    </transactionManager>

    <!-- 数据源的配置 -->
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>

  </environment>
</environments>

事务管理器

在Mybatis中,有两种类型的事务管理器,type="JDBC|MANAGED"

JDBC: 

        JDBC是别名,实际是Mybatis中的JdbcTransactionFactory工厂类, 该工厂类用来创建JdbcTransaction 事务管理器, 这个管理器直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。

MANAGED:

        MANAGED是别名,实际是Mybatis中的ManagedTransactionFactory工厂类, 该工厂类用来创建ManagedTransaction事务管理器, 但该管理器什么也没做,而是让容器来管理事务的整个生命周期,默认情况下,他会关闭连接,然而一些容器并不希望一些连接被关闭,所以需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为 , 他的部分源码:

public class ManagedTransaction implements Transaction {
    //省略部分...........
    @Override
    public void commit() throws SQLException {
        // Does nothing
    }

    @Override
    public void rollback() throws SQLException {
        // Does nothing
    }

    @Override
    public void close() throws SQLException {
    if (this.closeConnection && this.connection != null) {
      if (log.isDebugEnabled()) {
        log.debug("Closing JDBC Connection [" + this.connection + "]");
      }
      this.connection.close();
    }
  }

}
<transactionManager type="MANAGED">
  <property name="closeConnection" value="false"/>
</transactionManager>

         一般情况下,这两种事务管理器都不需要设置任何属性,他们都是类型别名,换句话说,你可以使用TransactionFactory接口实现类代替他们, 因为他们也是实现的TransactionFactory接口

public interface TransactionFactory {

  void setProperties(Properties props);

  //从存在的Connection,创建一个Transaction接口的实现类,或者使用第三方的
  Transaction newTransaction(Connection conn);
  
  //从数据源创建事务
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

}
/**
 * 管理事务: 包装一个数据库连接,处理连接的生命周期, 提交/回滚和关闭等。
 */
public interface Transaction {

  Connection getConnection() throws SQLException;

  void commit() throws SQLException;

  void rollback() throws SQLException;

  void close() throws SQLException;

  Integer getTimeout() throws SQLException;
  
}

使用这两个接口,你可以完全自定义Mybatis对事务的处理

数据源(dataSource)

        用于连接数据库,简化以前jdbc获取连接的繁琐步骤,分为 "有连接池" 和 "无连接池" 的数据源

Mybatis中有三种内建的数据源类型(即type="UNPOOLED  POOLED  JNDI"):

UNPOOLED:  通过UnPooledDataSourceFactory工厂类创建UnpooledDataSource实例, 这个数据源的实现会每次请求时打开和关闭连接

POOLED: 通过PooledDataSourceFactory工厂类创建PooledDataSource实例, 利用池的概念, 避免创建连接时的时间,常见属性有

                poolMaximumActiveConnections – 活动连接数,默认值:10

                poolMaximumIdleConnections – 空闲连接数。

JNDI : MyBatis会从JNDI服务上查找DataSource实例,然后返回使用, 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用

不用上面两种数据源 , 也可以通过实现DataSourceFactory接口来使用第三方数据源

public interface DataSourceFactory {

  void setProperties(Properties props);

  //自己实现DataSource接口,或使用第三方的
  DataSource getDataSource();

}
<!-- 比如使用C3P0数据源,连接至 PostgreSQL 数据库 -->
<dataSource type="org.myproject.C3P0DataSourceFactory">
  <property name="driver" value="org.postgresql.Driver"/>
  <property name="url" value="jdbc:postgresql:mydb"/>
  <property name="username" value="postgres"/>
  <property name="password" value="root"/>
</dataSource>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值