Mybatis配置

Mybatis配置文件并不复杂,它的所有元素如下:




    
    
    
    
    
    
    
        
            
            
        
    
    
    

需要注意的是,顺序不能颠倒,否则启动会发生异常.

1、properties属性

properties属性可以给系统配置一些运行参数,可以放在xml文件或properties文件中。mybatis提供了三种方式让我们使用properties:
property元素;
properties文件;
程序代码传递;

1.1 property元素:




    
        
        
        
        
    

    
        
            
            
                
                
                
                
            
        
    


这样就可以一次定义到处使用了

1.2 使用properties文件

这个是比较普遍的大家常用的方法。一来这个文件十分简单,里面就是存的键值对,二来可以吧多个键值对放在不同文件,以便于日后维护。
jdbc.properties如下:

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

在Mybatis中通过properties的属性resource来引入properties文件


1.3 使用程序传递方式传递参数

在真实的生产环境中,数据库密码需要保密。故一般都需要将用户名密码经过加密成为密文后,配置到properties文件中。假设提供了Utils.decode(cipferText)进行解密。那么创建SqlSessionFactory代码清单如下所示:

String resource = "mybatis-config.xml";
InputStream inputStream;
InputStream in = Resources.getResourceAsStream(resource);
Properties props = new Properties();
props.load(in);
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
props.put("jdbc.username",Utils.decode(username));
props.put("jdbc.password",Utils.decode(password));
inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,props);

2、settings设置

settings是mybatis中最复杂的配置,它能深刻的影响mybatis底层的运行,但是在大部分情况下,使用默认值便可以运行。下面是全量的配置案例:

    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

常见的几个设置的用法简介:

配置项 作用 配置选项说明 默认值
cacheEnabled 该配置影响所有映射器中配置缓存的全局开关 true/false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。在特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态 true/false false
aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使得带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载 true/false 版本3.1.4(不包含)之前true,之后false
autoMappingBehavior 指定mybatis应如何映射列到字段或属性。NONE表示取消自动映射;PARTIAL表示只会自动映射,没有定义嵌套结果集和映射结果集;FULL会自动映射任意的复杂结果集(无论是否嵌套) NONE/PARTIAL/FULL PARTIAL
defaultExecutorType 配置默认的执行器 。SIMPLE是普通的执行器;Reuse会重用预处理语句(Prepared statements);BATCH执行器将重用语句并执行批量更新 SIMPLE/REUSE/BATCH SIMPLE
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则映射,即从经典数据库列名A_COLUMN到经典java属性名aColumn的类似映射 true/false false

3、typeAliases 别名

由于类的全限定名很长,在多次需要使用的时候,比较不方便,在mybatis中允许定义一个简写来代替,这就是别名,分为系统定义和自定义别名。在mybatis中别名由类TypeAliasRegistry来定义(org.apache.ibatis.type.TypeAliasRegistry)。在mybatis中,别名不区分大小写。
3.1、自定义别名
由于现实开发中,存在许多自定义的对象需要重复使用,因此mybatis中也提供了用户自定义别名的规则。我们可以通过TypeAliasRegistry类的registerAlias方法注册,也可以采用配置文件或或者扫描方式来定义它。
3.1.1、使用配置文件定义

    
        
        
    

3.1.2、扫描
现实开发中可能存在大量的实体类,如果一个一个的配置就不适合了。因此mybatis还提供了扫描别名。如上配置:两个实体类位于同一包下,还可以这样配置:

    
        
    

3.1.3、注解配置别名
如果多个类同时包含User实体类,在通过包扫描后,可能会有冲突。则可以通过注解来区分。比如:

package com.ssm.pojo;
@Alias("user3")
public Class User{
  ... ...
}

这样就可以避免因为别名重名导致的扫描失败的问题。

4、typeHandler类型转换器
在JDBC中,需要在PreparedStatement对象中设置哪些已经预编译过的SQL语句的参数。执行SQL后,会通过ResultSet对象获取得到数据库的数据。而这些,Mybatis是根据数据库数据的类型通过TypeHandler来实现的。
在myBatis中,TypeHandler都需要实现接口org.apache.ibatis.type.TypeHandler,源码如下:

public interface TypeHandler  {
    void setParameter(java.sql.PreparedStatement preparedStatement, int i, T t, org.apache.ibatis.type.JdbcType jdbcType) throws java.sql.SQLException;

    T getResult(java.sql.ResultSet resultSet, java.lang.String s) throws java.sql.SQLException;

    T getResult(java.sql.ResultSet resultSet, int i) throws java.sql.SQLException;

    T getResult(java.sql.CallableStatement callableStatement, int i) throws java.sql.SQLException;
}

其中setParameter方法是使用TypeHandler通过PreparedStatement对象进行设置SQL参数的时候使用的具体方法,其中i是参数在SQL的下标,parameter是参数,jdbcType是数据库类型。
如果研究TypeHandler的源码,会发现其都实现了org.apache.ibatis.type.BaseTypeHandler,所以我们先看一下BaseTypeHandler的源码:

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
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;

/**
 * The base {@link TypeHandler} for references a generic type.
 * 

* Important: Since 3.5.0, This class never call the {@link ResultSet#wasNull()} and * {@link CallableStatement#wasNull()} method for handling the SQL {@code NULL} value. * In other words, {@code null} value handling should be performed on subclass. *

* * @author Clinton Begin * @author Simone Tripodi * @author Kzuki Shimizu */ public abstract class BaseTypeHandler extends TypeReference implements TypeHandler { /** * @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This field will remove future. */ @Deprecated protected Configuration configuration; /** * @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This property will remove future. */ @Deprecated public void setConfiguration(Configuration c) { this.configuration = c; } @Override 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 e) { 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: " + e, e); } } else { try { setNonNullParameter(ps, i, parameter, jdbcType); } catch (Exception e) { 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: " + e, e); } } } @Override public T getResult(ResultSet rs, String columnName) throws SQLException { try { return getNullableResult(rs, columnName); } catch (Exception e) { throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e); } } @Override public T getResult(ResultSet rs, int columnIndex) throws SQLException { try { return getNullableResult(rs, columnIndex); } catch (Exception e) { throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set. Cause: " + e, e); } } @Override public T getResult(CallableStatement cs, int columnIndex) throws SQLException { try { return getNullableResult(cs, columnIndex); } catch (Exception e) { throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement. Cause: " + e, e); } } public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; /** * @param columnName Colunm name, when configuration useColumnLabel is false */ public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException; public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException; public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException; }

我们简单分析一下源码:
1、这是个抽象类,实现了TypeHandler接口的四个方法,定义了4个抽象方法,需要其子类去实现。下面将会以StringTypeHandler来简单说明一下。
2、getResult方法:非空结果集是通过getNullableResult来实现。
3、setParameter方法:如果parameter与jdbcType同时为null,抛出异常。
4、getNullableResult用于存储过程。

下面通过StringTypeHandler 来加深了解TypeHandler:

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

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

/**
 * @author Clinton Begin
 */
public class StringTypeHandler extends BaseTypeHandler {

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

在mybatis中采用org.apache.ibatis.type.TypeHandlerRegistry类对象的register来进行注册。其源码如下(已删减部分)

/**
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public final class TypeHandlerRegistry {
  public TypeHandlerRegistry() {
    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    ... ...
    register(Byte[].class, new ByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
   ... ...
  }
}

自定义的TypeHandler一般是通过配置或扫描:
根据系统定义的可以知道,要实现TypeHandler就需要去实现接口TypeHandler或者继承BaseTypeHandler(其也实现了接口TypeHandler)。这里我们仿造一个StringTypeHandler。代码如下:

package com.ssm.chapter3.typehandler;

import org.apache.ibatis.type.JdbcType;
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;


/**
 * Created by czz on 2019/8/4.
 */
public class MyTypeHandler implements TypeHandler {
    Logger log = Logger.getLogger(MyTypeHandler.class);

    @Override
    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
            throws SQLException{
        log.info("String参数为: 【"+parameter+"】");
        ps.setString(i,parameter);
    }

    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException{
        String result = rs.getString(columnName);
        log.info("读取String参数-01 : 【"+result+"】");
        return result;
    }

    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException{
        String result = rs.getString(columnIndex);
        log.info("读取String参数-02 : 【"+result+"】");
        return result;
    }

    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException{
        String result = cs.getString(columnIndex);
        log.info("读取String参数-03 : 【"+result+"】");
        return result;
    }
}


定义完成之后,还需要额皮质完成系统才会读取它,注册它。

    
        
    

还可以显示启用TypeHandler,代码如下:

    
        
        
        
    


    


    

由于有时候自定义的类型会比较多,可以考虑使用包扫描的形式。但是这样就无法指定JavaType和jdbcType了,此时可以用注解处理。代码如下:

    
        
    
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyTypeHandler implements TypeHandler {
   ... ...
}

5、ObjectFactory(对象工厂)

当创建结果集时,Mybatis会使用一个对象工厂来创建这个结果集实例。在默认的情况下,Mybatis会使用其自定义的对象工厂------DefaultObjectFactory(org.apache.ibatis.reflection.DefaultObjectFactory),并给予配置。在大部分情况下,我们都不需要自定义返回规则,因为这些比较复杂且容易出错。更多的情况,可能是继承DefaultObjectFactory,通过一定的改写来完成我们所需要的工作。

6、插件

插件是mybatis中最强大和灵活的组件,同时也是最复杂最难以使用的的组件,而且因为它将覆盖mybatis底层对象的核心方法和属性,所以十分危险。

7、environments(运行环境)

在mybatis中,运行环境的主要作用是配置数据库信息,它可以配置多个数据库,一般而言只需要配置其中的一个就可以了。他下面又分为两个可配置的元素:事务管理器(TransactionManager)和数据源(DataSource)。运行环境配置,代码如下:

    
        
            
            
                
                
                
                
            
        
    

7.1、事务管理器(TransactionManager)
在mybatis中transactionManager提供了两个实现类,他们需要实现接口org.apache.ibatis.transaction.Transaction接口定义如下:

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.transaction;

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

public interface Transaction {

  Connection getConnection() throws SQLException;

  void commit() throws SQLException;

  void rollback() throws SQLException;

  void close() throws SQLException;

  Integer getTimeout() throws SQLException;

}

根据接口的方法可知,它主要的工作就是提交(commit),回滚(rollback)和关闭(close)数据库的事务。mybatis为Transaction接口提供了两个实现类JdbcTransaction和ManagedTransaction,因此对应着两个工厂JdbcTransactionFactory和ManagedTransactionFactory。这两个工厂都需要实现TransactionFactory接口,通过他们会生成Transaction对象。于是,可以把事务管理器配置成一下两种方式:



transactionFactory源码如下:

public interface TransactionFactory {
  default void setProperties(Properties props) {
    // NOP
  }
  Transaction newTransaction(Connection conn);
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

}

下面是JdbcTransactionFactory 的源码,通过源码可以更了解该工厂如何生产JdbcTransaction的。这部分源码相对来讲比较容易理解。

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.transaction.jdbc;

import java.sql.Connection;
import javax.sql.DataSource;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;

public class JdbcTransactionFactory implements TransactionFactory {
  @Override
  public Transaction newTransaction(Connection conn) {
    return new JdbcTransaction(conn);
  }
  @Override
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
}


当然如果不想采用mybatis给提供的规则,我们可以自定义事务工厂:

package com.ssm.chapter3.objectfactory;

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;

/**
 * Created by czz on 2019/8/5.
 */
public class MyTransaction extends JdbcTransaction implements Transaction {
    public MyTransaction(DataSource dataSource, TransactionIsolationLevel level,boolean autoCommit){
        super(dataSource,level,autoCommit);
    }
    
    public MyTransaction(Connection conn){
        super(conn);
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        return super.getConnection();
    }

    @Override
    public void rollback() throws SQLException{
        super.rollback();
    }
    
    @Override
    public void commit() throws SQLException{
        super.commit();
    }
    
    @Override
    public Integer getTimeout() throws SQLException{
        return super.getTimeout();
    }
    
}


package com.ssm.chapter3.objectfactory;

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;

/**
 * Created by czz on 2019/8/5.
 */
public class MyTransactionFactory implements TransactionFactory {
    @Override
    public void setProperties(Properties props){}

    @Override
    public Transaction newTransaction(Connection conn){
        return new MyTransaction(conn);
    }

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


配置自定义事务

type="com.learn.ssm.chapter4.transaction,MyTransactionFactory"

7.2environment数据源环境
environment的主要作用是配置数据库,在mybatis中,数据库通过PooledDataSourceFactory、UnpooledDataSourceFactory、JndiDataSourceFactory三个工厂类来提供。前两者会产生PooledDataSource、UnpooledDataSource对象,而JndiDataSourceFactory则会jndi的信息拿到外部容器实现的数据库连接对象。无论如何,这三个工厂类生成的产品都是一个实现了DataSource接口的数据库连接对象。配置方法分别如下所示:


7.2.1 UNPOOLED
采用非数据库池的管理方式,每次请求都会打开一个新的数据库连接,所以创建会比较慢。在一些对性能要求没那么高的场合可以使用。可以配置以下属性:
driver:数据库驱动名;
url
username
password
DefaultTransactionIsolationLevel:默认的连接事务隔离级别。

7.2.2 Pooled
利用池的概念将JDBC的connection对象组织起来。它开始会有一些空置,以及一些连接好的数据库连接。所以在请求时,无需再建立和验证,省去了创建新的连接实例时所必需的初始化和认证时间。它还空置最大连接数,以免过多的连接导致系统瓶颈。
除了UNPOOLED的属性外,会有更多属性用来配置POOLED数据源:
poolMaximumActiveConnections:
poolMaximumIdleConnections:
poolMaximumCheckoutTime:
poolTimeToWait:
poolPingQuery:
poolPingEnabled:
poolPingConnectionsNotUserFor:

7.2.3 JNDI
可以自定义数据源工厂,并进行配置


  
... ...


8、databaseIdProvider数据库厂商标识

主要用于给不同客户提供系统需要不同数据库连接时,配置如下:

    
        
        
        
    

标识SQL适用何种数据库:

    
    

9、引入映射器的方法

    
    
        
    

    
    
        
    

    
    
        
        
    

    
    
        
        
    

你可能感兴趣的:(Mybatis配置)