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 |
//
// 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
//
// 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);
}
}
<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>