SSM学习-Mybatis-Second-Mybatis配置

Mybatis配置

1.Mybatis概述

    Mybatis的配置文件总得来说比不算复杂,毕竟整个文件都是在为数据的持久化而服务的,它自身就已经为每个配置文件属性提供强大的支持,涵盖大部分code中的所需要的功能,但同时它灵活的特性也是为人所称道,大部分的配置都可以通过实现相对应的接口再重新定义,强大的不行,先来看看配置文件的元素清单

<?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">
<!--mybatis配置文件-->
<configuration>
    <properties/><!--配置运行参数,比数据库的名字,驱动之类,提高解耦-->

    <settings/><!--深刻影响底层的运行,可以修改自动映射,驼峰命名映射,级联规则等-->

    <typeAliases/><!--为类的全限定名起别名,可以在Mapper映射配置文件中作为resultMap type的值,除系统自动初始化一部分外,需自定义-->

    <typeHandlers/><!--类型处理器,负责javaType和jdbcType的相互转换,可自定义(实现接口typeHandler)-->

    <objectFactory/><!--对象工厂,结果集的生成原则,可自定义(实现接口ObjectFactory)-->

    <plugins/><!--插件-->

    <environments><!--环境变量,即运行环境,主要负责数据库的底层配置,可以配置多个数据库-->
        <environment><!--具体配置数据库-->
            <transactionManager/><!--事物管理器,主要是JdbcTransaction对象和ManagedTranscation对象,可自定义,分别实现TransactionFactory和Transaction-->
            <dataSource><!--数据源,UNPOOLED,POOLED,JNDI-->
                <property/>
            </dataSource>
        </environment>
    </environments>

    <databaseIdProvider/><!--数据库厂商标识,Mybatis移植性的挣扎-->

    <mappers/><!--配置映射器-->

</configuration>

2.具体配置

2.1 properties的配置

        properties的配置分为三种,第一种是直接在mybatis配置文件里进行配置,方便快速,但是信息不安全,与之相似的是第二种方法,即单独设置一个properties文件,采用文件读取的方式配置properties,叫第一种方法安全了许多,可是仍未满足一些用户对数据库保密的需求,最安全的方式莫过于第三种方法,properties配置数据库,但是利用代码实现去数据库密码等敏感数据实现配置,安全性较高,但是不灵活

2.1.1 直接配置(property子元素配置)

    

    <properties>
    <property name="database.driver" value="com.mysql.jdbc.Driver"/>
    <property name="database.url" value="jdbc:mysql://localhost:3306/ssm"/>
    <property name="database.username" value="root"/>
    <property name="database.password" value="database.password"/>
    </properties>

2.1.2 使用properties文件

        在resource文件下面新建jdbc.properties文件

database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/ssm
database.username=root
database.password=password

        mybatis配置文件里标注引用的文件为jdbc.properties

    <properties resource="jdbc.properties"></properties>

2.1.3 实用程序传递方式传递参数

String resource = "mybatis-config.xml"
InputStream InputStream;
InputStream in = Resource.getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(in);
String username = prop.getProperty("database.username");
String password = prop.getProperty("database.password");
//解密用户名密码,并重置属性
prop.put("database.username",CodeUtils.decode(username));
prop.put("database.password",CodeUtils.decode(password));
inputStream = Resource.getResourceAsStream(resource);
//实用程序覆盖的方式改变properties的属性参数
SqlSessionFactory = new SqlSessionFactoryBulider().build(inputStream,prop);
2.2 settings的配置

缓存cacheEnable:所有映射器的配置缓存的全局开关

级联延迟加载lazyLoadingEnable:所有的关联对象都会延迟加载

级联aggressiveLazyLoading:对带有延迟属性的对象实现完整加载

自动映射autoMappingBehavior:指定Mybatis如何自动映射列到字段或属性

自动映射mapUnderscoreToCamelCase:是否开启自动驼峰命名规则映射(A_COLUMN到aColumn)

执行器类型defaultExecutorType:配置默认执行器。SIMPLE,REUSE,BATCH值

    <settings>
        <setting name="cacheEnable" value="true"></setting>
        <setting name="lazyLoadingEnabled" value="true"></setting>
        <setting name="autoMappingBehavior" value="PARTIAL"></setting>
        <setting name="defaultExecutorType" value="SIMPLE"></setting>
        <setting name="mapUnderscoreToCamelCase" value="false"></setting>
    </settings>
2.3 typeAliases别名

    分为系统别名和自定义别名,org.apache.ibatis.type.TypeAliasRegistry定义,Mybatis不区分大小写

2.3.1 系统别名

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
TyepAliasRegistry代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.io.ResolverUtil.IsA;

public class TypeAliasRegistry {
    private final Map<String, Class<?>> TYPE_ALIASES = new HashMap();
//系统自定义别名
    public TypeAliasRegistry() {
        this.registerAlias("string", String.class);
        this.registerAlias("byte", Byte.class);
        this.registerAlias("long", Long.class);
        this.registerAlias("short", Short.class);
        this.registerAlias("int", Integer.class);
        this.registerAlias("integer", Integer.class);
        this.registerAlias("double", Double.class);
        this.registerAlias("float", Float.class);
        this.registerAlias("boolean", Boolean.class);
        this.registerAlias("byte[]", Byte[].class);
        this.registerAlias("long[]", Long[].class);
        this.registerAlias("short[]", Short[].class);
        this.registerAlias("int[]", Integer[].class);
        this.registerAlias("integer[]", Integer[].class);
        this.registerAlias("double[]", Double[].class);
        this.registerAlias("float[]", Float[].class);
        this.registerAlias("boolean[]", Boolean[].class);
        this.registerAlias("_byte", Byte.TYPE);
        this.registerAlias("_long", Long.TYPE);
        this.registerAlias("_short", Short.TYPE);
        this.registerAlias("_int", Integer.TYPE);
        this.registerAlias("_integer", Integer.TYPE);
        this.registerAlias("_double", Double.TYPE);
        this.registerAlias("_float", Float.TYPE);
        this.registerAlias("_boolean", Boolean.TYPE);
        this.registerAlias("_byte[]", byte[].class);
        this.registerAlias("_long[]", long[].class);
        this.registerAlias("_short[]", short[].class);
        this.registerAlias("_int[]", int[].class);
        this.registerAlias("_integer[]", int[].class);
        this.registerAlias("_double[]", double[].class);
        this.registerAlias("_float[]", float[].class);
        this.registerAlias("_boolean[]", boolean[].class);
        this.registerAlias("date", Date.class);
        this.registerAlias("decimal", BigDecimal.class);
        this.registerAlias("bigdecimal", BigDecimal.class);
        this.registerAlias("biginteger", BigInteger.class);
        this.registerAlias("object", Object.class);
        this.registerAlias("date[]", Date[].class);
        this.registerAlias("decimal[]", BigDecimal[].class);
        this.registerAlias("bigdecimal[]", BigDecimal[].class);
        this.registerAlias("biginteger[]", BigInteger[].class);
        this.registerAlias("object[]", Object[].class);
        this.registerAlias("map", Map.class);
        this.registerAlias("hashmap", HashMap.class);
        this.registerAlias("list", List.class);
        this.registerAlias("arraylist", ArrayList.class);
        this.registerAlias("collection", Collection.class);
        this.registerAlias("iterator", Iterator.class);
        this.registerAlias("ResultSet", ResultSet.class);
    }

    public <T> Class<T> resolveAlias(String string) {
        try {
            if (string == null) {
                return null;
            } else {
                String key = string.toLowerCase(Locale.ENGLISH);
                Class value;
                if (this.TYPE_ALIASES.containsKey(key)) {
                    value = (Class)this.TYPE_ALIASES.get(key);
                } else {
                    value = Resources.classForName(string);
                }

                return value;
            }
        } catch (ClassNotFoundException var4) {
            throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + var4, var4);
        }
    }
//使用registerAliases(Parameter para)方法注册别名
    public void registerAliases(String packageName) {
        this.registerAliases(packageName, Object.class);
    }

    public void registerAliases(String packageName, Class<?> superType) {
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil();
        resolverUtil.find(new IsA(superType), packageName);
        Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
        Iterator i$ = typeSet.iterator();

        while(i$.hasNext()) {
            Class<?> type = (Class)i$.next();
            if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
                this.registerAlias(type);
            }
        }

    }

    public void registerAlias(Class<?> type) {
        String alias = type.getSimpleName();
        Alias aliasAnnotation = (Alias)type.getAnnotation(Alias.class);
        if (aliasAnnotation != null) {
            alias = aliasAnnotation.value();
        }

        this.registerAlias(alias, type);
    }

    public void registerAlias(String alias, Class<?> value) {
        if (alias == null) {
            throw new TypeException("The parameter alias cannot be null");
        } else {
            String key = alias.toLowerCase(Locale.ENGLISH);
            if (this.TYPE_ALIASES.containsKey(key) && this.TYPE_ALIASES.get(key) != null && !((Class)this.TYPE_ALIASES.get(key)).equals(value)) {
                throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + ((Class)this.TYPE_ALIASES.get(key)).getName() + "'.");
            } else {
                this.TYPE_ALIASES.put(key, value);
            }
        }
    }

    public void registerAlias(String alias, String value) {
        try {
            this.registerAlias(alias, Resources.classForName(value));
        } catch (ClassNotFoundException var4) {
            throw new TypeException("Error registering type alias " + alias + " for " + value + ". Cause: " + var4, var4);
        }
    }
//使用getTypeAliases() 获得别名
    public Map<String, Class<?>> getTypeAliases() {
        return Collections.unmodifiableMap(this.TYPE_ALIASES);
    }
}

2.3.2 自定义别名

        利用mybatis-config.xml配置文件<typeAliases>

    <typeAliases><!--为pojo设置一个别名-->
        <typeAlias alias="role" type="Role"/>
        <typeAlias alias="user" type="User"/>
    </typeAliases>

        当自定义别名较多时,可以采取包扫描,自动将POJO小写变成别名

    <typeAliases><!--为pojo设置一个别名-->
        <package name="pojo"/>
    </typeAliases>

        当包扫描出现重名时,利用注解加以区分

import org.apache.ibatis.type.Alias;
//当包扫描出现重名时,利用注解加以区分
@Alias("role1")
public class Role{

    private Long id;
    private String roleName;
    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}
2.4 typeHandler类型转换器

2.4.1 

    Mybatis根据typeHandler来获得数据库的数据类型,typeHandler主要实现了数据库类型jdbcType和JavaType的相互转换,但是大部分的类型转换已经被定义好了,只是有些枚举类型需要我们自己自定义typeHandler

    源码分析typeHandler

//
// 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> {
	//通过PreparedStatement对象设置SQL参数的具体方法
    void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;
    //这3个getResult()方法,作用为从JDBC结果集中获取数据进行转换
    //使用列名column
    T getResult(ResultSet var1, String var2) throws SQLException;
    //使用下标
    T getResult(ResultSet var1, int var2) throws SQLException;
    //存储过程专用
    T getResult(CallableStatement var1, int var2) throws SQLException;
}

BaseTypeHandler类

//
// 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;
//BaseTypeHandler是个抽象类,且继承TypeReference抽象类并实现TypeHandler接口
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
    protected Configuration configuration;

    public BaseTypeHandler() {
    }

    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) {
            	//当parameter,jdbcType同时为空时会抛出异常
                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);
            }
        }

    }

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

        return rs.wasNull() ? null : result;
    }

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

        return rs.wasNull() ? null : result;
    }

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

        return cs.wasNull() ? null : result;
    }

    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;
    //getNullableResult()方法用于存储过程
    public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}

        BaseTypeHandler是个抽象类,子类需要实现四个抽象方法,自身实现TypeHandler接口的四个方法,非空结果集是通过getNullableResult()方法获取的

我们来看看StringTypeHandler是怎样具体实现BaseTypeHandler类的

//
// 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 class StringTypeHandler extends BaseTypeHandler<String> {
    public StringTypeHandler() {
    }

    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }

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

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

    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}

        根据StringTypeHandler类写法,我们就可以模仿并且自定义自己TypeHandler,但是一般情况下我们是不必自定义的,Mybatis系统定义已经满足我们大部分的需求,但是在应用枚举的时候,因为枚举有自己特殊转换规则,需要我们自定义typeHandler

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
import org.apache.log4j.Logger;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @ProjectName: Chapter3
 * @Package: com.learn.ssm.chapter3.typehandler
 * @ClassName: MyTypeHandler
 * @Description: 创建自定义的typeHandler
 * @Author: Joe
 * @CreateDate: 13/04/2018 15:01
 * @UpdateUser: 更新者
 * @UpdateDate: 13/04/2018 15:01
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
/*
**这两个注解是配合包扫描的形式配置自定义typeHandler,因为包扫描配置无法在Mapper指定对应的jdbcType和javaType
@MappedTypes(String.class)
@MappedJdbcTypes(jdbcType.VARCHAR)
*/
public class MyTypeHandler implements TypeHandler<String>{

    Logger logger = Logger.getLogger(MyTypeHandler.class);


    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)throws SQLException{
        logger.info("设置string参数【"+parameter+"】");
        ps.setString(i, parameter);
    }


    public String getResult(ResultSet resultSet, String columnName/*列名*/)throws SQLException{
        String result = resultSet.getString(columnName);
        logger.info("读取string参数1(列名)【"+result+"】");
        return result;
    }


    public String getResult(ResultSet resultSet, int columnIndex/*下标*/)throws SQLException{
        String result = resultSet.getString(columnIndex);
        logger.info("读取参数2(下标)【"+result+"】");
        return result;
    }


    public String getResult(CallableStatement callableStatement, int columnIndex)throws SQLException{
        String result = callableStatement.getString(columnIndex);
        logger.info("读去参数3(用于存储的那个歌厅Result)【"+result+"】");
        return result;
    }
}

        自定义typeHandler就是继承BaseTypeHandler类或者实现TypeHandler接口,我们选择继承BaseTypeHandler类,并实现这个类的四个抽象方法,因为是模仿StringTypeHandler写的,所以与其差别不大,自定义规则之后,我们需要配置typeHandler,就在mybatis配置文件中<typeHandler>标签,方法有两种:一是指出自定义typeHandler要转换的两种类型,或者直接指定typeHandler是哪个类

    <typeHandlers>
        <!--自定义typeHander不多时采用此种方法配置typeHandler-->
        <typeHandler jdbcType="VARCHAR" javaType="string" handler="MyTypeHandler"></typeHandler>
        <!--如果枚举类型很多,不采用以上方法配置,转而采用包扫描方案是配置,但是自定义的那个typeHandler1就需要注解 @MappedTypes(String.class) 和
            注解 @MappedJdbcTypes(jdbcType.VARCHAR) 处理,详见MyTypeHandler类-->
        <!--<package name="com.learn.ssm.chapter3.typehandler"/>-->
    </typeHandlers>

2.4.2 枚举typeHandler

        Mybatis已经定义两个类作为枚举类型的支持:

            EnumOrdinalTypeHandler:根据枚举数组下标索引方式进行匹配,是枚举类型默认转换类 

            EnumTypeHandler:根据使用名称转化对应的枚举                  

/**
 * @ProjectName: Chapter3
 * @Package: PACKAGE_NAME
 * @ClassName: SexEnum
 * @Description: java类作用描述
 * @Author: Joe
 * @CreateDate: 13/04/2018 16:40
 * @UpdateUser: 更新者
 * @UpdateDate: 13/04/2018 16:40
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public enum SexEnum {
    MALE(1,"我是男生"), FEMALE(0,"我是女生");

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    SexEnum(int id, String name){
        this.id = id;
        this.name = name ;
    }

    public SexEnum getSexById(int id){
        for (SexEnum sex : SexEnum.values()){
            if (sex.getId() == id){
                return sex;
            }
        }
        return null;
    }


}

数据库语句

create table t_user(
id int(12) not null,
user_name varchar(60) not null,
password varchar(60) not null,
sex char(1) not null,
mobile varchar(20) not null,
tel varchar(20),
email varchar(20),
note varchar(512),
primary key(id)); 

mysql> insert into t_user values('1','joe','123456','1','133333333','0755-8888','[email protected]','note…');

UserMapper.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="UserMapper">
    <resultMap id="userMapper" type="user"><!--这里的type可以小写是因为Mybatis配置文件中定义了类的别名typeAlias-->
        <result property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="password" column="password"/>
        <result property="sex" column="sex"
                typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
        <result property="mobile" column="mobile"/>
        <result property="tel" column="tel"/>
        <result property="email" column="email"/>
        <result property="note" column="note"/>
    </resultMap>

        <select id="getUser" resultMap="userMapper" parameterType="long">
            SELECT id, user_name, password, sex, mobile, tel, email, note
            FROM t_user
            WHERE id = #{id}
        </select>
</mapper>

简单测试

/**
 * @ProjectName: Chapter3
 * @Package: PACKAGE_NAME
 * @ClassName: Chapter3Main
 * @Description: Main运行代码
 * @Author: Joe
 * @CreateDate: 12/04/2018 10:28
 * @UpdateUser: 更新者
 * @UpdateDate: 12/04/2018 10:28
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;


public class Chapter3Main {

    public static void main(String[] args){
        Logger log = Logger.getLogger(Chapter3Main.class);
        SqlSession sqlSession = null;
        try {
            sqlSession =SqlSessionFactoryUtils.openSqlSession();
            //使用EnumOrdinalTypeHandler定义UserMapper.xml的查询操作
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user1 = userMapper.getUser(1L);
            log.info(user1.getSex().getName());

        }finally {
            if (sqlSession != null){
                sqlSession.close();
            }
        }
    }
}

运行日志

DEBUG 2018-04-16 15:51:51,162 org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
DEBUG 2018-04-16 15:51:51,246 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-16 15:51:51,249 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-16 15:51:51,249 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-16 15:51:51,249 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-16 15:51:51,354 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC Connection
DEBUG 2018-04-16 15:51:51,571 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 121295574.
DEBUG 2018-04-16 15:51:51,571 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@73ad2d6]
DEBUG 2018-04-16 15:51:51,573 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: SELECT id, user_name, password, sex, mobile, tel, email, note FROM t_user WHERE id = ? 
DEBUG 2018-04-16 15:51:51,599 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
DEBUG 2018-04-16 15:51:51,614 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
 INFO 2018-04-16 15:51:51,615 Chapter3Main: 我是女生
DEBUG 2018-04-16 15:51:51,615 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@73ad2d6]
DEBUG 2018-04-16 15:51:51,616 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@73ad2d6]
DEBUG 2018-04-16 15:51:51,616 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 121295574 to pool.

Process finished with exit code 0
2.5 ObjectFactory对象工厂

        当创建结果集时,Mybatis会使用一个对象工厂来创建结果集实例,默认使用DefaultObjectFactory类,如果有需求的话可以自定义对象工厂,为了避免出错,一般选择继承DefaultObjectFactory类

import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.log4j.Logger;

import java.util.List;
import java.util.Properties;

/**
 * @ProjectName: Chapter3
 * @Package: PACKAGE_NAME
 * @ClassName: MyObjectFactory
 * @Description: 实现自定义的ObjectFactory,创建结果集
 * @Author: Joe
 * @CreateDate: 16/04/2018 17:19
 * @UpdateUser: 更新者
 * @UpdateDate: 16/04/2018 17:19
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public class MyObjectFactory extends DefaultObjectFactory {

        private static final long serialVersionUID = 1L;

        Logger logger = Logger.getLogger(MyObjectFactory.class);

        private Object temp = null;

        public void setProperties(Properties porperties){
            super.setProperties(porperties);
            logger.info("初始化参数:【"+porperties.toString()+"】");
        }

        //方法1
    public <T> T create(Class<T> type, List<Class<?>> construtorArgTypes, List<Object> constructorArgs){
            T result = super.create(type, construtorArgTypes, constructorArgs);
            logger.info("创建对象:"+ result.toString());
            temp = result;
            return result;
    }

    //方法二
    public <T> T create(Class<T> type){
            T result = super.create(type);
            logger.info("创建对象:"+result.toString());
            logger.info("是否和上次创建的是同一个对象:【"+(temp == result)+"】");
            return result;
    }

    public <T> boolean isCollection(Class<T> type){
            return super.isCollection(type);
    }
}
mybatis配置文件进行配置
    <objectFactory type="MyObjectFactory">
        <property name="propl" value="value1"></property>
    </objectFactory>

运行结果

        Mybatis创建了一个List对象和一个Role对象,实际上先调用的方法一,然后调用的方法二,最后生成同一个对象,并最终返回一个适配的Role对象

DEBUG 2018-04-17 14:32:32,250 org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
 INFO 2018-04-17 14:32:32,325 MyObjectFactory: 初始化参数:【{propl=value1}】
DEBUG 2018-04-17 14:32:32,354 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-17 14:32:32,354 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-17 14:32:32,355 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-17 14:32:32,355 org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
DEBUG 2018-04-17 14:32:32,470 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC Connection
DEBUG 2018-04-17 14:32:32,708 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 121295574.
DEBUG 2018-04-17 14:32:32,708 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@73ad2d6]
DEBUG 2018-04-17 14:32:32,710 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: SELECT id, role_name AS roleName, note FROM t_role WHERE id = ? 
DEBUG 2018-04-17 14:32:32,740 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
 INFO 2018-04-17 14:32:32,760 MyObjectFactory: 创建对象:[]    方法一
 INFO 2018-04-17 14:32:32,760 MyObjectFactory: 创建对象:[]    方法二
 INFO 2018-04-17 14:32:32,760 MyObjectFactory: 是否和上次创建的是同一个对象:【true】
 INFO 2018-04-17 14:32:32,762 MyObjectFactory: 创建对象:Role@20322d26
 INFO 2018-04-17 14:32:32,762 MyObjectFactory: 创建对象:Role@20322d26
 INFO 2018-04-17 14:32:32,764 MyObjectFactory: 是否和上次创建的是同一个对象:【true】
DEBUG 2018-04-17 14:32:32,765 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
 INFO 2018-04-17 14:32:32,765 Chapter3Main: joe
DEBUG 2018-04-17 14:32:32,766 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@73ad2d6]
DEBUG 2018-04-17 14:32:32,766 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@73ad2d6]
DEBUG 2018-04-17 14:32:32,766 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 121295574 to pool.

Process finished with exit code 0
2.6 plugins插件(补充ing)
2.7 environment运行环境

        主要作用就是用来配置数据库,可以配置多个数据库,分为事物管理器配置(transactionManager)和数据源(dataSource)配置。实际工作中大部分还是采用spring对数据源和事务管理

mybatis-config.xml

    <!--数据库环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${database.driver}"/>
                <property name="url" value="${database.url}"/>
                <property name="username" value="${database.username}"/>
                <property name="password" value="${database.password}"/>
            </dataSource>
        </environment>
    </environments>

transactionManager的类型有两种,一个是JDBC(使用jdbcTransactionFactory生成对象,并以jdbc方式对数据库进行操作),另一种是MANAGED(生成ManagedTransaction对象,事务操作交个容器处理)

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

package org.apache.ibatis.transaction;

import java.sql.Connection;
import java.sql.SQLException;

public interface Transaction {
      //通过connection对象连接数据库
    Connection getConnection() throws SQLException;
      //提交操作
    void commit() throws SQLException;
      //会滚操作
    void rollback() throws SQLException;
      //关闭连接
    void close() throws SQLException;
}

自定义事务工厂

import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Properties;

/**
 * @ProjectName: Chapter3
 * @Package: PACKAGE_NAME
 * @ClassName: MyTransactionFactory
 * @Description: 自定义工厂事务
 * @Author: Joe
 * @CreateDate: 17/04/2018 15:17
 * @UpdateUser: 更新者
 * @UpdateDate: 17/04/2018 15:17
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */


public class MyTransactionFactory implements TransactionFactory {

    public void setProperties(Properties properties) {
    }

    public Transaction newTransaction(Connection connection) {
        return newTransaction(connection);
    }

    public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
        return new MyTransaction(dataSource, level, autoCommit);
    }
}

自定义事务类

import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.jdbc.JdbcTransaction;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @ProjectName: Chapter3
 * @Package: PACKAGE_NAME
 * @ClassName: MyTransaction
 * @Description: 自定义事务类
 * @Author: Joe
 * @CreateDate: 17/04/2018 15:27
 * @UpdateUser: 更新者
 * @UpdateDate: 17/04/2018 15:27
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public class MyTransaction extends JdbcTransaction implements Transaction {
    public MyTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
        super(ds, desiredLevel, desiredAutoCommit);
    }


    public MyTransaction(Connection connection) {
        super(connection);
    }
    @Override
    public Connection getConnection() throws SQLException{
        return super.getConnection();
    }

    @Override
    public void commit() throws SQLException{
        super.commit();
    }

    @Override
    public void rollback() throws SQLException{
        super.rollback();
    }

    @Override
    public void close() throws SQLException{
        super.close();
    }

}


数据源环境分为三种:

UNPOOLED:如名字一般,非数据池管理方式,每次请求都会打开新的链接,适合性能要求低的场合

POOLED:提前建立好连接,无需再建立,并且拥有非池技术属性,并添加了一些属性来控制连接池(例如

                poolPingQuery:为发送到数据库的侦测查询,检验连接是否正常)

JNDI:为了EJB或者应用服务器这类容器使用,容器可以集中,也可以在外部配置,

            主要是配置initial_context上下文和data_source

自定义数据源工厂:当我们需要第三方数据源时,可以通过自定义数据源工厂(实现DataSourceFactory接口)来提供支持

示例源码

import org.apache.ibatis.datasource.DataSourceFactory;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * @ProjectName: Chapter3
 * @Package: PACKAGE_NAME
 * @ClassName: MyDataSourceFactory
 * @Description: 自定义数据源工厂
 * @Author: Joe
 * @CreateDate: 17/04/2018 15:21
 * @UpdateUser: 更新者
 * @UpdateDate: 17/04/2018 15:21
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public class MyDataSourceFactory implements DataSourceFactory {

    private Properties properties = null;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public DataSource getDataSource() {
        DataSource dataSource = null;
        return  dataSource;
    }
}

然后在mybatis-config.xml进行配置

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="MyDataSourceFactory">
                <property name="driver" value="${database.driver}"/>
                <property name="url" value="${database.url}"/>
                <property name="username" value="${database.username}"/>
                <property name="password" value="${database.password}"/>
            </dataSource>
        </environment>
    </environments>
2.8 databaseIdProvider(数据库厂商标识)

mybatis-config.xml

    <databaseIdProvider type="DB_VENDOR">
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>

Mapper.xml

        <select id="getUser" resultMap="userMapper" parameterType="long" databaseId="oracle">
            SELECT id, user_name, password, sex, mobile, tel, email, note
            FROM t_user
            WHERE id = #{id}
        </select>
2.9 引入映射器

方法一:文件路径引入

   <!--映射文件-->
    <mappers>
        <mapper resource="RoleMapper.xml"/>
        <mapper resource="UserMapper.xml"/>
    </mappers>

方法二:包扫描引入

    <mappers>
        <package name="com.ssm.UserMapper.xml"/>
    </mappers>

方法三:实用类注册引入

    <mappers>
        <mapper class="com.ssm.UserMapper"/>
    </mappers>

方法四:用映射文件引入

<mappers>
      <mapper url="file://com.ssm.UserMapper.xml"/>
</mappers>

3.Mybatis感触

        感觉Mybatis真的作为数据的持久化真的是非常灵活的,可是灵活是一把双刃剑,灵活也带来了复杂,很多配置都是可以自定义的,个人感觉还是利大于弊的,希望能在日后的学习生活中能够加深这些自定义配置的用法 

猜你喜欢

转载自blog.csdn.net/redistant/article/details/79939868