MyBatis配置
目標:MyBatis官网 https://mybatis.org/mybatis-3/zh/configuration.html
掌握properties 元素的用法
掌握setting 元素的用法
掌握typeAliases 的用法
重点掌握typeHandler在Mybatis中的用法
了解ObjectFactory的作用
了解environments 的配置
了解databaseIdProvider 的用法
掌握如何有效引入映射器
概述
"http://mybatis.org/dtd/mybatis-3-config.dtd">
properties 属性
properties 属性可以给系统配置一些运行参数,可以放在xml文件或者properties文件中,而不是java代码中。
优点:方便参数修改,而不引起代码重新编译
Mybatis提供3种方式使用properties:
propertie子元素
properties文件
程序代码传递
propertie子元素
"http://mybatis.org/dtd/mybatis-3-config.dtd">
properti
es文件
"http://mybatis.org/dtd/mybatis-3-config.dtd">
type="com.learn.ssm.chapter4.datasource.DbcpDataSourceFactory">
type="com.learn.ssm.chapter4.databaseidprovider.MyDatabaseIdProvider">
properties
database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/chapter4
database.username=root
database.password=123456
程序代码传递
public static SqlSessionFactory getSqlSessionFactory() {
synchronized (LOCK) {
if (sqlSessionFactory != null) {
return sqlSessionFactory;
}
String resource = "mybatis-config.xml";
InputStream inputStream;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
//采用程序传递加密参数,启用它之前,修改用户密码为密文,可参考main方法......
// InputStream in = Resources.getResourceAsStream("jdbc.properties");
// Properties props = new Properties();
// props.load(in);
// String username = props.getProperty("database.username");
// String password = props.getProperty("database.password");
// // 解密用户和密码,并在属性中重置
// props.put("database.username", CodeUtils.decode(username));
// props.put("database.password", CodeUtils.decode(password));
// inputStream = Resources.getResourceAsStream(resource);
// // 使用程序传递的方式覆盖原有的properties属性参数
// sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, props);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return sqlSessionFactory;
}
}
总结:Mybatis使用properties用36种方式,优先级:properey--》 properties文件--》程式传递
setting 元素
setting是MyBatis中最复杂的配置,它能深刻影响MyBatis底层运行,但部分使用默认方式即可。
一般使用:自动映射,驼峰影视,级联映射,是否启动缓存,执行器类型。
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置名 | 描述 | 有效值 | 默认值 | ||||||
---|---|---|---|---|---|---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true | |||||
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false | |||||
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods )。 |
true | false | false (在 3.4.1 及之前的版本中默认为 true) | |||||
multipleResultSetsEnabled | 是否允许单个语句返回多结果集(需要数据库驱动支持)。 | true | false | true | |||||
useColumnLabel | 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 | true | false | true | |||||
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False | |||||
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL | ||||||
autoMappingUnknownColumnBehavior | 指定发现自动映射目标未知列(或未知属性类型)的行为。NONE : 不做任何反应WARNING : 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN )FAILING : 映射失败 (抛出 SqlSessionException ) |
NONE, WARNING, FAILING | NONE | ||||||
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE | ||||||
defaultStatementTimeout | 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) | ||||||
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) | ||||||
defaultResultSetType | 指定语句默认的滚动策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) | 未设置 (null) | |||
safeRowBoundsEnabled | 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False | |||||
safeResultHandlerEnabled | 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 | true | false | True | |||||
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False | |||||
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 | SESSION | STATEMENT | SESSION | |||||
jdbcTypeForNull | 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 | OTHER | ||||||
lazyLoadTriggerMethods | 指定对象的哪些方法触发一次延迟加载。 | 用逗号分隔的方法列表。 | equals,clone,hashCode,toString | ||||||
defaultScriptingLanguage | 指定动态 SQL 生成使用的默认脚本语言。 | 一个类型别名或全限定类名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver | ||||||
defaultEnumTypeHandler | 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) |
一个类型别名或全限定类名。 | org.apache.ibatis.type.EnumTypeHandler | ||||||
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 | true | false | false | |||||
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回 null 。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) |
true | false | false | |||||
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 未设置 | ||||||
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
proxyFactory | 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) | |||||
vfsImpl | 指定 VFS 的实现 | 自定义 VFS 的实现的类全限定名,以逗号分隔。 | 未设置 | ||||||
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) |
true | false | true | |||||
configurationFactory | 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) |
一个类型别名或完全限定类名。 | 未设置 | ||||||
shrinkWhitespacesInSql | 从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5) | true | false | false | |||||
defaultSqlProviderType | Specifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type (or value ) attribute on sql provider annotation(e.g. @SelectProvider ), when these attribute was omitted. |
A type alias or fully qualified class name | Not set |
一个配置完整的 settings 元素的示例如下:
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
当这样配置时,Blog
可以用在任何使用 domain.blog.Blog
的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
别名 | 映射的类型 |
---|---|
_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 |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
类型处理器(typeHandlers)
MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。
提示 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。
类型处理器 | Java 类型 | JDBC 类型 |
---|---|---|
BooleanTypeHandler |
java.lang.Boolean , boolean |
数据库兼容的 BOOLEAN |
ByteTypeHandler |
java.lang.Byte , byte |
数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler |
java.lang.Short , short |
数据库兼容的 NUMERIC 或 SMALLINT |
IntegerTypeHandler |
java.lang.Integer , int |
数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler |
java.lang.Long , long |
数据库兼容的 NUMERIC 或 BIGINT |
FloatTypeHandler |
java.lang.Float , float |
数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler |
java.lang.Double , double |
数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler |
java.math.BigDecimal |
数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler |
java.lang.String |
CHAR , VARCHAR |
ClobReaderTypeHandler |
java.io.Reader |
- |
ClobTypeHandler |
java.lang.String |
CLOB , LONGVARCHAR |
NStringTypeHandler |
java.lang.String |
NVARCHAR , NCHAR |
NClobTypeHandler |
java.lang.String |
NCLOB |
BlobInputStreamTypeHandler |
java.io.InputStream |
- |
ByteArrayTypeHandler |
byte[] |
数据库兼容的字节流类型 |
BlobTypeHandler |
byte[] |
BLOB , LONGVARBINARY |
DateTypeHandler |
java.util.Date |
TIMESTAMP |
DateOnlyTypeHandler |
java.util.Date |
DATE |
TimeOnlyTypeHandler |
java.util.Date |
TIME |
SqlTimestampTypeHandler |
java.sql.Timestamp |
TIMESTAMP |
SqlDateTypeHandler |
java.sql.Date |
DATE |
SqlTimeTypeHandler |
java.sql.Time |
TIME |
ObjectTypeHandler |
Any | OTHER 或未指定类型 |
EnumTypeHandler |
Enumeration Type | VARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值) |
EnumOrdinalTypeHandler |
Enumeration Type | 任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。 |
SqlxmlTypeHandler |
java.lang.String |
SQLXML |
InstantTypeHandler |
java.time.Instant |
TIMESTAMP |
LocalDateTimeTypeHandler |
java.time.LocalDateTime |
TIMESTAMP |
LocalDateTypeHandler |
java.time.LocalDate |
DATE |
LocalTimeTypeHandler |
java.time.LocalTime |
TIME |
OffsetDateTimeTypeHandler |
java.time.OffsetDateTime |
TIMESTAMP |
OffsetTimeTypeHandler |
java.time.OffsetTime |
TIME |
ZonedDateTimeTypeHandler |
java.time.ZonedDateTime |
TIMESTAMP |
YearTypeHandler |
java.time.Year |
INTEGER |
MonthTypeHandler |
java.time.Month |
INTEGER |
YearMonthTypeHandler |
java.time.YearMonth |
VARCHAR 或 LONGVARCHAR |
JapaneseDateTypeHandler |
java.time.chrono.JapaneseDate |
DATE |
mybatis-自定义TypeHandler
步骤1:实现TypeHandler接口
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
/**
@author
-
java中的boolean和jdbc中的char之间转换;true-Y;false-N
*/
//方式一:
@MappedJdbcTypes(JdbcType.CHAR)
@MappedTypes(Boolean.class)
public class BooleanTypeHandler implements TypeHandler {/* (non-Javadoc)
- @see org.apache.ibatis.type.TypeHandler#getResult(java.sql.ResultSet, java.lang.String)
*/
@Override
public Object getResult(ResultSet resultSet, String columnLabel) throws SQLException {
String str = resultSet.getString(columnLabel);
Boolean rt = Boolean.FALSE;
if (str.equalsIgnoreCase("Y")){
rt = Boolean.TRUE;
}
return rt;
}
@Override
public Object getResult(ResultSet resultSet, int columnIndex) throws SQLException {
String str = resultSet.getString(columnIndex);
Boolean rt = Boolean.FALSE;
if (str.equalsIgnoreCase("Y")){
rt = Boolean.TRUE;
}
return rt;
}/* (non-Javadoc)
- @see org.apache.ibatis.type.TypeHandler#getResult(java.sql.CallableStatement, int)
*/
@Override
public Object getResult(CallableStatement arg0, int arg1)
throws SQLException {
Boolean b = arg0.getBoolean(arg1);
return b == true ? "Y" : "N";
}
/* (non-Javadoc)
- @see org.apache.ibatis.type.TypeHandler#setParameter(java.sql.PreparedStatement, int, java.lang.Object, org.apache.ibatis.type.JdbcType)
*/
@Override
public void setParameter(PreparedStatement arg0, int arg1, Object arg2,
JdbcType arg3) throws SQLException {
Boolean b = (Boolean) arg2;
String value = (Boolean) b == true ? "Y" : "N";
arg0.setString(arg1, value);
}
}
- @see org.apache.ibatis.type.TypeHandler#getResult(java.sql.ResultSet, java.lang.String)
步骤2:在Mybatis配置中注册该TypeHandler
步骤3:在映射配置文件中使用该TypeHander(如果第一步使用了注解,此处可以省略)
3.1在resultMap的定义中对对应列定义typeHandler
这里只能是在select的时候才会使用自定义的TypeHandler处理对应的映射关系,如果要在insert或者update时使用则需要在sql定义中添加相应的内容
3.2在resultMap的定义中对对应列定义typeHandler
SELECT LAST_INSERT_ID()
insert into hotel_order_category (category_type, category_name, allocate_time,
promise_time, last_operator, update_time,
is_cancel, status1, status2,
phone_list, create_time)
values (#{categoryType,jdbcType=INTEGER}, #{categoryName,jdbcType=VARCHAR}, #{allocateTime,jdbcType=INTEGER},
#{promiseTime,jdbcType=INTEGER}, #{lastOperator,jdbcType=VARCHAR}, #{updateTime,jdbcType=TIMESTAMP},
#{isCancel,jdbcType=CHAR,typeHandler=com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler},
#{status1,jdbcType=CHAR}, #{status2,jdbcType=CHAR},
#{phoneList,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP})
#mybatis-enumtypehandler和enumordinaltypehandler的区别
mybatis对枚举类型提供了两种类型支持:EnumTypeHandler和EnumOrdinalTypeHandler。
EnumTypeHandler是mybatis默认的枚举类型转换器,如果pojo类中使用了枚举类型,而配置文件没有指定类型转换类,mybatis将使用EnumTypeHandler处理枚举属性。EnumTypeHandler的将把枚举类的name进行存储,枚举类的name即枚举类名。参考:http://mybatis.github.io/mybatis-3/zh/configuration.html
EnumOrdinalTypeHandler是mybatis提供的另一种转换器,顾名思义这个转换类使用了枚举类的ordinal属性作为数据库存储信息,由于ordinal属性是int类型的,按照官网的说明数据库中对应资源应该是int或double类型的,但是个人测试过程中MYSQL的varchar字段也可以存储。
总结:EnumTypeHandler和EnumOrdinalTypeHandler的区别主要是数据库中存储字段的类型差别,由于EnumOrdinalTypeHandler使用枚举类型的ordinal作为存储,所以必须使用数字类型字段存储。
MyBatis中ObjectFactory简介
MyBatis 每次创建结果对象实例时,它使用一个 ObjectFactory 实例来完成。默认的ObjectFactory仅会按照配置结果类型的默认构造方法或者指定构造方法来创建对象实例。如果想重写默认的 ObjectFactory,你可以创建你自己的。比如:
// ExampleObjectFactory.java
//自定义的ObjectFactory
public class ExampleObjectFactory extends DefaultObjectFactory {
//使用默认构造方法创建对象实例
public Object create(Class type) {
return super.create(type);
}
//有构造参数列表和构造参数值列表的创建对象实例的方式
public Object create(Class type, List constructorArgTypes, List
//为自定义ObjectFactory设置配置参数
public void setProperties(Properties properties) {
super.setProperties(properties);
}
}
ObjectFactory 接口很简单。它包含两个创建用的方法,一个是处理默认构造方法的,另外一个是处理带参数构造方法的。最终,setProperties 方法可以被用来配置 ObjectFactory。在 初 始化 你 的 ObjectFactory 实例 后 , objectFactory 元素 体 中定 义的 属 性会 被传 递 给setProperties 方法。
一个例子: 假设实体对象实现了自定义的InitialEntity接口,则在创建对象完成之后必须调用InitialEntity接口的init方法:
package cd.itcast.mybatis.myobjectfactory;
public interface InitialEntity {
void init();
}
假设有一个实体StockOutcomeBillItem对象用来记录销售出库单明细,该对象再设置完值后,需要调用count()方法来完成总金额的计算:
package cd.itcast.mybatis.myobjectfactory;
public class StockOutcomeBillItem {
private Long id;
private Product product;
private Integer number;
private BigDecimal price;
private BigDecimal totalAmount;
//getter & setter
public void count(){
this.totalAmount=this.number*this.price;
}
}
该对象在实例化完成后需要调用count()方法来完成totalAmount属性的计算。要完成这个逻辑,只需要让该类实现定义的InitialEntity接口即可:
package cd.itcast.mybatis.myobjectfactory;
public class StockOutcomeBillItem implements InitialEntity{
private Long id;
//other properties;
//getter & setter
public void init() {
this.count();
}
private void count(){
this.totalAmount=this.number*this.price;
}
}
接下来,只需要完成能辨别InitialEntity接口的对象并调用其中的方法即可:
package cd.itcast.mybatis.myobjectfactory;
public class InitialObjectFactory extends DefaultObjectFactory {
private static final long serialVersionUID = 1L;
@Override
public T create(Class type) {
return super.create(type);
}
@Override
//注意,在DefaultObjectFactory的create(Class type)方法中调用的是
//create(Class,List constructorArgTypes,List
}
接下来只需要注册这个ObjectFactory即可:
以上就是mybatis中objectfactory的简单应用,关于objectfactory更多的实现细节,可以通过阅读mybatis代码去研究。
叩丁狼教育关注
MyBatis配置文件environments和子元素transactionManager、dataSource解析
< MyBatis ObjectFactoryMyBatis与Spring的整合步骤 >
Java一对一答疑,帮助有志青年!使用QQ在线辅导,哪里不懂问哪里,整个过程都是一对一,学习更有针对性。和作者直接交流,不但提升技能,还提升 Level;当你决定加入我们,你已然超越了 90% 的程序员。猛击这里了解详情。
在 MyBatis 中,运行环境主要的作用是配置数据库信息,它可以配置多个数据库,一般而言只需要配置其中的一个就可以了。
它下面又分为两个可配置的元素:事务管理器(transactionManager)、数据源(dataSource)。
在实际的工作中,大部分情况下会采用 Spring 对数据源和数据库的事务进行管理,这些我们教程后面都会进行讲解。本节我们会探讨 MyBatis 自身实现的类。
运行环境配置,代码如下所示。
这里用到两个元素:transactionManager 和 environment。
transactionManager(事务管理器)
在 MyBatis 中,transactionManager 提供了两个实现类,它需要实现接口 Transaction(org.apache.ibatis.transaction.Transaction),它的定义代码如下所示。
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,如图 1 所示。
图 1 Transaction的实现类
于是它对应着两种工厂:JdbcTransactionFactory 和 ManagedTransactionFactory,这个工厂需要实现 TransactionFactory 接口,通过它们会生成对应的 Transaction 对象。于是可以把事务管理器配置成为以下两种方式:
这里做简要的说明。
JDBC 使用 JdbcTransactionFactory 生成的 JdbcTransaction 对象实现。它是以 JDBC 的方式对数据库的提交和回滚进行操作。
MANAGED 使用 ManagedTransactionFactory 生成的 ManagedTransaction 对象实现。它的提交和回滚方法不用任何操作,而是把事务交给容器处理。在默认情况下,它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
不想采用 MyBatis 的规则时,我们可以这样配置:
实现一个自定义事务工厂,代码如下所示。
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, TransactionlsolationLevel level, boolean autoCommit) {
return new MyTransaction(dataSource, level, autoCommit);
}}
这里就实现了 TransactionFactory 所定义的工厂方法,这个时候还需要事务实现类 MyTransaction,它用于实现 Transaction 接口,代码如下所示。
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);
}
public Connection getConnection() throws SQLException {
return super.getConnection();
}
public void commit() throws SQLException {
super.commit();
}
public void rollback() throws SQLException {
super.rollback();
}
public void close() throws SQLException {
super.close();
}
public Integer getTimeout() throws SQLException {
return super.getTimeout();
}}
这样就能够通过自定义事务规则,满足特殊的需要了。
environment 数据源环境
environment 的主要作用是配置数据库,在 MyBatis 中,数据库通过 PooledDataSource Factory、UnpooledDataSourceFactory 和 JndiDataSourceFactory 三个工厂类来提供,前两者对应产生 PooledDataSource、UnpooledDataSource 类对象,而 JndiDataSourceFactory 则会根据 JNDI 的信息拿到外部容器实现的数据库连接对象。
无论如何这三个工厂类,最后生成的产品都会是一个实现了 DataSource 接口的数据库连接对象。
由于存在三种数据源,所以可以按照下面的形式配置它们。
论述一下这三种数据源及其属性。
1. UNPOOLED
UNPOOLED 采用非数据库池的管理方式,每次请求都会打开一个新的数据库连接,所以创建会比较慢。在一些对性能没有很高要求的场合可以使用它。
对有些数据库而言,使用连接池并不重要,那么它也是一个比较理想的选择。UNPOOLED 类型的数据源可以配置以下几种属性:
driver 数据库驱动名,比如 MySQL 的 com.mysql.jdbc.Driver。
url 连接数据库的 URL。
username 用户名。
password 密码。
defaultTransactionIsolationLevel 默认的连接事务隔离级别,关于隔离级别,后面教程中会讨论。
传递属性给数据库驱动也是一个可选项,注意属性的前缀为“driver.”,例如 driver.encoding=UTF8。它会通过 DriverManager.getConnection(url,driverProperties)方法传递值为 UTF8 的 encoding 属性给数据库驱动。
2. POOLED
数据源 POOLED 利用“池”的概念将 JDBC 的 Connection 对象组织起来,它开始会有一些空置,并且已经连接好的数据库连接,所以请求时,无须再建立和验证,省去了创建新的连接实例时所必需的初始化和认证时间。它还控制最大连接数,避免过多的连接导致系统瓶颈。
除了 UNPOOLED 下的属性外,会有更多属性用来配置 POOLED 的数据源,如表 1 所示:
名称 | 说明 |
---|---|
poolMaximumActiveConnections | 是在任意时间都存在的活动(也就是正在使用)连接数量,默认值为 10 |
poolMaximumIdleConnections | 是任意时间可能存在的空闲连接数 |
poolMaximumCheckoutTime | 在被强制返回之前,池中连接被检出(checked out)的时间,默认值为 20 000 毫秒(即 20 秒) |
poolTimeToWait | 是一个底层设置,如果获取连接花费相当长的时间,它会给连接池打印状态日志,并重新尝试获取一个连接(避免在误配置的情况下一直失败),默认值为 20 000 毫秒(即 20 秒)。 |
poolPingQuery | 为发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中,并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一个恰当的错误消息。 |
poolPingEnabled | 为是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置 poolPingQuery 属性(最好是一个非常快的 SQL),默认值为 false。 |
poolPingConnectionsNotUsedFor | 为配置 poolPingQuery 的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值为 0(即所有连接每一时刻都被侦测——仅当 poolPingEnabled 为 true 时适用)。 |
3. JNDI
数据源 JNDI 的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这种数据源配置只需要两个属性:
1)initial_context
用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。initial_context 是个可选属性,如果忽略,那么 data_source 属性将会直接从 InitialContext 中寻找。
2)data_source
是引用数据源实例位置上下文的路径。当提供 initial_context 配置时,data_source 会在其返回的上下文中进行查找;当没有提供 initial_context 时,data_source 直接在 InitialContext 中查找。
与其他数据源配置类似,它可以通过添加前缀“env.”直接把属性传递给初始上下文(InitialContext)。比如 env.encoding=UTF8,就会在初始上下文实例化时往它的构造方法传递值为 UTF8 的 encoding 属性。
MyBatis 也支持第三方数据源,例如使用 DBCP 数据源,那么需要提供一个自定义的 DataSourceFactory,代码如下所示。
public class DbcpDataSourceFactory implements DataSourceFactory {
private Properties props = null;
public void setProperties(Properties props) {
this.props = props;
}
public DataSource getDataSource() {
DataSource dataSource = null;
dataSource = BasicDataSourceFactory.createDataSource(props);
return dataSource;
}}
然后进行如下配置:
这样 MyBatis 就会采用配置的数据源工厂来生成数据源了。
databaseIdProvider 用法
databaseIdProvider 元素主要是支持多种不同厂商的数据库
package com.learn.ssm.chapter4.databaseidprovider;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.log4j.Logger;
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";
} else if (MyDatabaseIdProvider.DATEBASE_TYPE_ORACLE
.equals(dbProductName)) {
return "oracle";
} else {
return null;
}
}
}
有效引入映射器
首先定义接口
package com.learn.ssm.chapter4.mapper;
import java.util.List;
import com.learn.ssm.chapter4.pojo.Role;
public interface RoleMapper {
public int insertRole(Role role);
public int deleteRole(Long id);
public int updateRole(Role role);
public Role getRole(Long id);
public List findRoles(String roleName);
}
其次,给出xml
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
用文件路劲引入映射器
-
用包名引入引射器
-
用类注册引入映射器
4.用userMapperxml 引入映射器
-