Mybatis学习-配置、做用域和生命周期

核心配置文件:Mybatis-config.xml
Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息html

配置(configuration)

在mybatis-config.xml文件中标签都有规定的顺序,须要按照如下顺序添加
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?java

属性(properties)

咱们能够经过properties来实现引用文件。Mybatis的一些属性能够在外部进行配置,并能够进行动态替换。你既能够在典型的 Java 属性文件中配置这些属性,也能够在properties元素的子元素中设置mysql

  1. 编写一个配置文件(db.properties)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/learn?serverTimezone=GMT&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456789
  1. 在mybatis-config.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">

<!--核心配置文件-->
<configuration>

    <!--引入外部配置文件-->
    <properties resource="db.properties" />
    
    <!--也能够配置文件中写一部分,标签中写一部分-->
    <!--优先使用外部配置文件中的配置-->
    <properties resource="db.properties">
    	<property name="username" value="root"/>
        <property name="pwd" value="123456789"/>
    </properties>

    <environments default="test">
       
        <environment id="test">
            <transactionManager type="JDBC"/>
            <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>

    <!--每个Mapper.xml都须要在Mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>
  1. 测试
@Test
public void test() {
    //获取SQLSession对象
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    try {

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();

        for (User user : userList) {
           System.out.println(user);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //关闭SQLSession
        sqlSession.close();
    }
}

Mybatis会先读取properties元素体内的指定属性,再根据resource属性读取类路径下属性文件。因此外部配置文件中编写的配置会覆盖内部标签编写的配置,外部配置文件拥有更高优先级sql

设置(setting)

这是Mybatis中极为重要的调整设置,他们会改变Mybatis的运行时行为数据库

更多设置请参考:https://mybatis.org/mybatis-3/zh/configuration.html#settingsapache

环境配置(environments)

Mybatis能够配置成适应多种环境
尽管能够配置多个环境,但每一个SQLSessionFactory实例只能选择一种环境
Mybatis默认的事务管理器就是JDBC,数据源是POOLED安全

<environments default="test">	<!--须要使用的环境-->
    
    <!--环境一-->
    <environment id="development">		<!--id:每套environment的惟一标识-->
        <transactionManager type="JDBC"/>	<!--事务管理器的配置-->
        <dataSource type="POOLED">			<!--数据源的配置-->
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/learn?serverTimezone=GMT&amp;useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123456789"/>
        </dataSource>
    </environment>

    <!--环境二-->
    <environment id="test">
        <transactionManager type="JDBC"/>
        <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>

类型别名(typeAliases)

类型别名为Java类型设置一个短的名字,它仅用于XML配置,存在的意义仅在于用来减小类彻底限定名的冗余bash

<typeAliases>
    <typeAlias alias="User" type="com.luoqing.model.User"/>
</typeAliases>

也能够指定一个包名,Mybatis会在包名下搜索须要的JavaBeansession

<typeAliases>
    <package name="com.luoqing.model" />
</typeAliases>

每个在包名下的JavaBean,在没有注解的状况下,会使用Bean首字母小写的非限定类名来做为它的别名
若是有注解则其别名为其注解值mybatis

//这个类的别名为user
@Alias("user")
public class User {
    ……
}

在实体类比较少的时候,使用第一种方式。若是实体类十分多,建议使用第二种

类型处理器(typeHandlers)

Mybatis使用typeHandlers将数据库中字段的类型转换为java类中属性的类型,或将java类中属性的类型转换为数据库中字段的类型

经过Configuration对象获取

@Test
public void myTest() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    TypeHandlerRegistry typeHandlerRegistry = sqlSession.getConfiguration().getTypeHandlerRegistry();
    Collection<TypeHandler<?>> list = typeHandlerRegistry.getTypeHandlers();
    System.out.println(list.size());
    for (TypeHandler<?> typeHandler : list) {
        System.out.println(typeHandler.getClass().getName());
    }

    sqlSession.close();

}

执行结果以下。如下全部的处理器类位于mybatis-X.X.X.jar/org/apache/ibatis/type中

40
org.apache.ibatis.type.InstantTypeHandler
org.apache.ibatis.type.MonthTypeHandler
org.apache.ibatis.type.JapaneseDateTypeHandler
org.apache.ibatis.type.UnknownTypeHandler
org.apache.ibatis.type.DateTypeHandler
org.apache.ibatis.type.CharacterTypeHandler
org.apache.ibatis.type.BigIntegerTypeHandler
org.apache.ibatis.type.SqlxmlTypeHandler
org.apache.ibatis.type.LocalDateTimeTypeHandler
org.apache.ibatis.type.ArrayTypeHandler
org.apache.ibatis.type.YearTypeHandler
org.apache.ibatis.type.FloatTypeHandler
org.apache.ibatis.type.NStringTypeHandler
org.apache.ibatis.type.BooleanTypeHandler
org.apache.ibatis.type.ByteTypeHandler
org.apache.ibatis.type.ClobTypeHandler
org.apache.ibatis.type.BigDecimalTypeHandler
org.apache.ibatis.type.ByteArrayTypeHandler
org.apache.ibatis.type.BlobTypeHandler
org.apache.ibatis.type.DateOnlyTypeHandler
org.apache.ibatis.type.YearMonthTypeHandler
org.apache.ibatis.type.SqlDateTypeHandler
org.apache.ibatis.type.OffsetTimeTypeHandler
org.apache.ibatis.type.LongTypeHandler
org.apache.ibatis.type.TimeOnlyTypeHandler
org.apache.ibatis.type.ZonedDateTimeTypeHandler
org.apache.ibatis.type.BlobInputStreamTypeHandler
org.apache.ibatis.type.LocalDateTypeHandler
org.apache.ibatis.type.IntegerTypeHandler
org.apache.ibatis.type.StringTypeHandler
org.apache.ibatis.type.BlobByteObjectArrayTypeHandler
org.apache.ibatis.type.ShortTypeHandler
org.apache.ibatis.type.NClobTypeHandler
org.apache.ibatis.type.LocalTimeTypeHandler
org.apache.ibatis.type.ClobReaderTypeHandler
org.apache.ibatis.type.SqlTimestampTypeHandler
org.apache.ibatis.type.SqlTimeTypeHandler
org.apache.ibatis.type.ByteObjectArrayTypeHandler
org.apache.ibatis.type.OffsetDateTimeTypeHandler
org.apache.ibatis.type.DoubleTypeHandler

Mybatis已经为咱们写好了40个类型处理器
其中DateTypeHandlers的源码以下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

public class DateTypeHandler extends BaseTypeHandler<Date> {
    public DateTypeHandler() {
    }

    /**
    	获取到对应的java类型的对象,将其转换为jdbc类型
    */
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        ps.setTimestamp(i, new Timestamp(parameter.getTime()));
    }

    /**
    	获取到对应列的jdbc类型的对象,将其转换为java类型
    */
    public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnName);
        return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
    }

    /**
    	根据索引获取到对应的数据的jdbc类型将其转换为java类型
    */
    public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnIndex);
        return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
    }

    /**
    	这个方法用在存储过程当中。将jdbc类型转换为java类型
    */
    public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);
        return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
    }
}

它的父类BaseTypeHandler<T>

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.ibatis.session.Configuration;

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
    /** @deprecated */
    @Deprecated
    protected Configuration configuration;

    public BaseTypeHandler() {
    }

    /** @Deprecated表示此方法或者类不推荐使用,可是不表明不能用*/
    /** @deprecated */
    @Deprecated
    public void setConfiguration(Configuration c) {
        this.configuration = c;
    }

    
    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 {
                /** jdbcType是一个枚举类型 */
                /** 将对应的jdbc类型设置为null */
                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);
            }
        }

    }

    public T getResult(ResultSet rs, String columnName) throws SQLException {
        try {
            return this.getNullableResult(rs, columnName);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + var4, var4);
        }
    }

    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        try {
            return this.getNullableResult(rs, columnIndex);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set.  Cause: " + var4, var4);
        }
    }

    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        try {
            return this.getNullableResult(cs, columnIndex);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement.  Cause: " + var4, var4);
        }
    }

    //定义了四个抽象方法,并在上面接口方法的实现中使用了它们
    //具体的实现交给子类去完成
    public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException;

    public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}

BaseTypeHandler是一个抽象类,也是类型处理器的基类。它做为TypeHandler接口的初步实现,实现了TypeHandler的四个方法;还另外定义了四个抽象方法,也就是DateTypeHandler中的四个方法。系统定义的40个TypeHandler方法都继承自BaseTypeHandler

实现的接口TypeHandler<T>

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public interface TypeHandler<T> {
    void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

    T getResult(ResultSet var1, String var2) throws SQLException;

    T getResult(ResultSet var1, int var2) throws SQLException;

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

若是咱们要自定义typeHandler时:

  • 继承BaseTypeHandler类
  • 实现TypeHandler接口

通常不须要自定义,使用默认的就够了

映射器(mappers)

MapperRegistry:注册绑定咱们的Mapper文件

方式一:

<!-- 使用相对于类路径的资源引用,在resource文件夹中 -->
<mappers>
  <mapper resource="com/luoqing/dao/UserMapper.xml"/>
</mappers>

方式二:使用class文件绑定注册

<!-- 使用映射器接口实现类的彻底限定类名 -->
<mappers>
  <mapper class="com.luoqing.dao.UserMapper.xml"/>
</mappers>

注意:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

方式三:

<!-- 将包内的映射器接口实现所有注册为映射器 -->
<mappers>
  <package name="com.luoqing.dao"/>
</mappers>

注意:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

方式四:使用映射器接口实现类的彻底限定名(由于基本不使用,在此很少赘述,如要学习请移步官方文档)
https://mybatis.org/mybatis-3/zh/configuration.html#mappers

做用域(Scope)和生命周期

不一样做用域和生命周期类别是相当重要的,由于错误的使用会致使很是严重的并发问题

SqlSessionFactoryBuilder

一旦建立了 SqlSessionFactory,就再也不须要它了。所以 SqlSessionFactoryBuilder 实例的最佳做用域是方法做用域(也就是局部方法变量)。你能够重用 SqlSessionFactoryBuilder 来建立多个 SqlSessionFactory 实例,但最好仍是不要一直保留着它,以保证全部的 XML 解析资源能够被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被建立就应该在应用的运行期间一直存在,没有任何理由丢弃它或从新建立另外一个实例。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复建立屡次。所以 SqlSessionFactory 的最佳做用域是应用做用域。最简单的就是使用单例模式或者静态单例模式。

SqlSession

每一个线程都应该有它本身的 SqlSession 实例。SqlSession 的实例不是线程安全的,所以是不能被共享的,因此它的最佳的做用域是请求或方法做用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也毫不能将 SqlSession 实例的引用放在任何类型的托管做用域中,好比 Servlet 框架中的 HttpSession。每次收到 HTTP 请求,就能够打开一个 SqlSession,返回一个响应后,就关闭它。这个关闭操做很重要,为了确保每次都能执行关闭操做,你应该把这个关闭操做放到 finally 块中。下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

在全部代码中都遵循这种使用模式,能够保证全部数据库资源都能被正确地关闭。

相关文章
相关标签/搜索