MyBatis简介(三)

(4)typeHandler类型转换器
typeHandler作用是转换jdbcType和javaType,MyBatis中存在系统定义typeHandler和自定义typeHandler,MyBatis会根据jdbcType和javaType类型自动选择typeHandler类型;
系统:大部分无需显式声明
在这里插入图片描述
在这里插入图片描述
用户自定义typeHandler
对于一些特殊的转换规则,如枚举,就需要自定义一个tyleHandler了,可以选择implements typeHandler或entends BaseTypeHandler;示例如下:
实现类:

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

	@Override	
       public String getResult(ResultSet rs, String columnName) throws SQLException {
		String result = rs.getString(columnName);
		logger.info("在返回的结果集根据列名读取string参数1【" + result+"】");
		return result;
	}

	@Override
	public String getResult(ResultSet rs, int columnIndex) throws SQLException {
		String result = rs.getString(columnIndex);
		logger.info("在返回的结果集根据下标读取string参数2【" + result+"】");
		return result;
	}

	@Override
	public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
		String result = cs.getString(columnIndex);
		logger.info("在存储过程读取string参数3【" + result+"】");
		return result;
	}
}

配置typeHandler:单个配置或批量配置(包扫描)

<typeHandlers>
	<typeHandler jdbcType="VARCHAR" javaType="string" handler="cn.infocore.mybatis.typehandler.MyTypeHandler" />
</typeHandlers>
<typeHandlers>
	<package name="cn.infocore.mybatis.typehandler" />
</typeHandlers>

//启用包扫描注册的时候需要注解:
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyTypeHandler implements TypeHandler<String> {}

使用自定义typeHandler:
1)指定与定义一致的jdbcType和javaType;
2)直接使用实现类

<resultMap id="roleMapper" type="role">
	<result property="id" column="id" />
	<result property="roleName" column="role_name" jdbcType="VARCHAR" javaType="string" />
	<result property="note" column="note" typeHandler="cn.infocore.mybatis.typehandler.MyTypeHandler" />
</resultMap>
<select id="getRole" parameterType="long" resultMap="roleMapper">
	selectid, role_name, note from t_role where id = #{id}
</select>

<select id="findRoles" parameterType="string" resultMap="roleMapper">
	select id, role_name, note from t_role where role_name like 
	concat('%', #{roleName, jdbcType=VARCHAR,javaType=string}, '%')
</select>

<select id="findRoles2" parameterType="string" resultMap="roleMapper">
	select id, role_name, note from t_role where note like 
	concat('%', #{note,typeHandler=cn.infocore.mybatis.typehandler.MyTypeHandler}, '%')
</select>

枚举typeHandler:虽然系统自定义了两个,但一般不常用,还是需要自己定义;
系统:
-EnumOrdinalTypeHandler根据枚举数组下标索引匹配;
-EnumTypeHandler根据名称转换;
-自定义:同上String的例子;

(5)ObjectFactory对象工厂
在默认和大部分情况下,MyBatis会使用其定义的对象工厂DefaultObjectFactory来完成创建结果集实例;自定义ObjectFactory,需要implements ObjectFactory或者extends DefaultObjectFactory;

public class MyObjectFactory extends DefaultObjectFactory{
	private static final long serialVersionUID = 7820951972813645768L;
	private Object temp=null;
	//方法2
	@Override
	public <T> T create(Class<T> type) {
		T result=super.create(type);
		System.out.println("创建对象:"+result.toString());
		System.out.println("是否是同一个对象:"+(temp==result)); //true
		return result;
	}
        //方法1
	@Override
	public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
		T result=super.create(type, constructorArgTypes, constructorArgs);
		System.out.println("创建对象:"+result.toString());
		temp=result;
		return result;
	}

	@Override
	public <T> boolean isCollection(Class<T> type) {
		return super.isCollection(type);
	}

	@Override
	public void setProperties(Properties props) {
		super.setProperties(props);
		System.out.println("初始化参数:【"+props.toString()+"】");
	}
}

配置MyObjectFactory:这样MyBatis就会采用配置的MyObjectFactory来生成结果集对象;

<objectFactory type="cn.infocore.mybatis.objectFactory.MyObjectFactory">
	<property name="prop1" value="value1"/>
</objectFactory>

(6)插件
插件很灵活和强大,但也十分危险,因为它会覆盖MyBatis底层对象的核心方法和属性;

(7)environments(运行环境)
主要作用是配置数据库,支持配置多个数据库,但一般只需要一个;可分为事务管理器(transactionManager)和数据源(dataSource);

<environments default="development">
    <environment id="development">
      <!--事务管理器,采用的是JDBC管理器方式和MANAGED方式-->
      <transactionManager type="JDBC"/> 
      <dataSource type="POOLED"><!--POOLED代表采用MyBatis内部提供的连接池方式-->
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/xx_db"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>

JDBC:使用JdbcTransactionFactory生成的JdbcTransaction对象实现,以JDBC的方式对数据库的提交和回滚进行操作;
MANAGED:使用ManagedTransactionFactory生成的ManagedTransaction对象实现,它的提交和回滚方法不用任何操作,而是把事务交给容器处理,默认情况下,它会关闭连接,而一些容器并不希望这么做,因此需要将claseConnection设置为false;

当然,也可以自定义TransactionFactory,满足特殊要求;只需要定义类并配置即可;
-自定义事务类、事务工厂

public class MyTransaction extends JdbcTransaction implements Transaction{
	public MyTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
		super(ds, desiredLevel, desiredAutoCommit);
	}

	public MyTransaction(Connection conn) {
		super(conn);
	}

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

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

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

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

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

public class MyTransactionFactory implements TransactionFactory{
	@Override
	public Transaction newTransaction(Connection conn) {
		return new MyTransaction(conn);
	}

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

	@Override
	public void setProperties(Properties props) {}
}

-配置:

<transactionManager type="cn.infocore.mybatis.MyTransactionFactory"/>

数据源类型:
UNPOOLED:由UnpooledDataSourceFactory工厂类产生UnpooledDataSource类对象;采用非数据库池的管理方式,每次请求都会打开一个新的数据库连接,所以创建比较慢;可配置数据库驱动名driver、连接数据库urlusernamepassword、事务隔离级别defaultTransactionIsolationLevel,驱动属性可通过DriverManager.getConnection(url,props)设置;
POOLED: 由PooledDataSourceFactory工厂类产生PooledDataSource类对象;利用池将JDBC的Connection对象组织起来,开始会有一些空置和已经连接好的数据库连接,所以请求时,不需要再建立和验证,比较快;还能空置最大连接数,避免过多连接导致系统瓶颈;除了UNPOOLED的属性外,还可以配置:
poolMaximumActiveConnections:最大活动连接数,默认10;
poolMaximumIdleConnections:最大空闲连接数,默认5,最好设置为0;
poolMaximumCheckoutTime:最大可回收时间,即当达到最大活动连接数时,此时如果有程序获取连接,则检查最先使用的连接,看其是否超出了该时间,如果超出了该时间,则可以回收该连接,默认20s;
poolTimeToWait:没有连接时,重新尝试获取连接以及打印日志的时间间隔(默认20s;
poolPingQuery:检查连接正确的语句,默认为"NO PING QUERY SET",即没有,使用会导致抛异常
poolPingEnabled:是否开启ping检测,启用需设置可执行的SQL,默认false;
poolPingConnectionsNotUsedFor:设置ping检测时间间隔,通常用于检测超时连接,默认为0,即所有连接每一时刻都被侦测,当然仅当 poolPingEnabled 为 true 时适用;
JNDI:由JndiDataSourceFactory工厂类根据JNDI的信息拿到外部容器实现的数据库连接对象;适用于EJB或应用服务器;属性:
initial_context用来在InitialContext中寻找上下文,如忽略,data_source属性将直接从InitialContext中寻找;
data_source:引用数据源实例位置上下文的路径;
与其他数据源配置类似,可以通过前缀“env.”直接把属性传递给初始上下文;
也支持第三方数据库,需要提供一个自定义的DataSourceFactory(implements DataSourceFactory),然后配置;

(8)databaseIdProvider数据库厂商标识
—系统定义:
支持多种不同厂商的数据库,支持MyBatis的移植性,便于在多数据库环境下使用;

<databaseIdProvider type="DB_VENDOR">
	<property name="Oracle" value="oracle" />
	<property name="MySQL" value="mysql" />
	<property name="DB2" value="db2" />
</databaseIdProvider>

property元素的属性name是数据库名称,名字可以通过Connection的getMetaData().getDatabaseProductName()获取;value是别名,在MyBatis中可以通过这个别名标识一条SQL使用哪种数据库运行;示例如下:表示使用Oracle数据库;

<delete id="deleteRole" parameterType="long" databaseId="oracle">
	delete from t_role where t_id=#{id}
</delete>

注意:我们在使用多数据库SQL时需要配置databaseIdProvidertype属性,配置后,系统优先取得和数据库配置一致的SQL;如果未配置,则取没有databaseId的SQL,可以当做默认值;如果databaseId与系统数据库匹配不到,那就会抛出异常;

—自定义:

public class MyDatabaseIdProvider implements DatabaseIdProvider {
	private static final String DATEBASE_TYPE_DB2 = "DB2";
	private static final String DATEBASE_TYPE_MYSQL = "MySQL";
	private static final String DATEBASE_TYPE_ORACLE = "Oralce";
	private Logger log = Logger.getLogger(MyDatabaseIdProvider.class);

	@Override  //读取配置的参数
	public void setProperties(Properties props) {
		log.info(props);
	}

	@Override
	public String getDatabaseId(DataSource dataSource) throws SQLException {
		Connection connection = dataSource.getConnection();//获取当前数据库连接
		//当前数据库连接名字
		String dbProductName = connection.getMetaData().getDatabaseProductName();
		if (MyDatabaseIdProvider.DATEBASE_TYPE_DB2.equals(dbProductName)) {
			return "db2";
		} else if (MyDatabaseIdProvider.DATEBASE_TYPE_MYSQL
				.equals(dbProductName)) {
			return "mysql"; //匹配SQL中指定的databaseId
		} else if (MyDatabaseIdProvider.DATEBASE_TYPE_ORACLE
				.equals(dbProductName)) {
			return "oracle";
		} else {
			return null;
		}
	}
}
<databaseIdProvider type="cn.infocore.mybatis.MyDatabaseIdProvider ">
	<property name="msg" value="自定义DatabaseIdProvider " /> //配置的参数
</databaseIdProvider>

总之,系统规则是根据数据库的name对应的value去匹配SQL的databaseId,不匹配就异常;自定义规则就是根据自定义DatabaseIdProvider中getDatabaseId()返回的值去匹配SQL的databaseId,不匹配,那就异常;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值