MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
优点:
缺点:
需要手动编写SQL语句和映射规则,某些情况下会加大工作量
官网帮助文档:http://www.mybatis.org/mybatis-3/zh/index.html
SqlSessionFactory可以通过两种方式进行创建,一种是java代码生成,一种是读取XML配置文件生成。一般大家都使用XML模式进行创建,因为修改时比较方便,方便日后的管理,其次看起来也比较直观。
这是一个简单mybatis的配置文件,只配置了数据库。一般都是以mybatis-config.xml命名
有了数据库环境,我们就可以简单生成SqlSessionFactory了
// 配置文件放到了resources文件夹中
// 如果你放到了一个包中,你可以这样找到它 com/lzx/config/mybatis-config.xml
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);//读取配置文件
MySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 配置数据库
PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis_studydb");
dataSource.setUsername("root");
dataSource.setPassword("");
// 关闭事务的自动提交
dataSource.setDefaultAutoCommit(false);
// 采用Mybatis的JDBC的事务方式
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
// 加入映射器
configuration.addMapper(BlogMapper.class);
// 创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration)
mybatis中SqlSession是它的核心接口,有两个实现类:DefaultSqlSession和SqlSessionManager,其中DefaultSqlSession是在单线程中使用的,SqlSessionManager是在多线程中使用的。
SqlSession共有一下三个作用:
获取Mapper接口
发送SQL给数据库
控制数据库事务
//这里的sqlSessionFactory是上面SqlSessionFactory创建出来的·
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
sqlSessionFactory.commit();
} catch (Exception e){
sqlSessionFactory.rollback();
} finally {
session.close();
}
映射器是MyBtis中最为重要、最复杂的组件。可以通过XML文件和注解的形式去实现。可以用来配置以下内容:
这里我们暂时先了解一下它,因为它最为重要,我们以后会单独去学习掌握。
映射器接口:
@Repository
public interface BillingInfoDAO {
BillingInfoEntity queryById(int id);
}
XML方式创建映射器:
注解实现映射器:
public interface BillingInfoDAO {
//这里不推荐使用,较为复杂的sql语句不便于管理
@select(select invoice_id,billing_address,billing_city,billing_state,
billing_country,billing_postalcode from invoice where invoice_id=#{id})
BillingInfoEntity queryById(int id);
}
了解MyBatis配置文件的所有元素
接下来我们开始掌握这些元素的使用,接下来的所有配置都是在configuration里面完成的,注意这些元素的顺序一定要按照上面的顺序,不可随意放置, MyBatis的配置文件一般以mybatis-config.xml来命名,放置到类的加载路径下。
为了方便管理,我们一般使用properties文件进行数据库的连接配置。创建jdbc.properties文件,放置classpath路径下。方便我们配置数据库。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_studydb
jdbc.username=root
jdbc.password=123456
接下来我们就可以把properties和它的子元素进行替换即可
settings是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。大部分情况下保持默认值运行即可。
一个配置完整的 settings 元素的示例如下:
下面是settings配置项的详细说明:
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。 | true|false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。 | true|false | false |
aggressiveLazyLoading | 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods). | true|false | false(truein≤3.4.1) |
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,FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE就是普通的执行器;REUSE执行器会重用预处理语句(preparedstatements);BATCH执行器将重用语句并执行批量更新。 | SIMPLEREUSEBATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | 任意正整数 | NotSet(null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | NotSet(null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。 | true|false | False |
safeResultHandlerEnabled | 允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false。 | true|false | True |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camelcase)映射,即从经典数据库列名A_COLUMN到经典Java属性名aColumn的类似映射。 | true|false | False |
localCacheScope | MyBatis利用本地缓存机制(LocalCache)防止循环引用(circularreferences)和加速重复嵌套查询。默认值为SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为STATEMENT,本地会话仅用在语句执行上,对相同SqlSession的不同调用将不会共享数据。 | SESSION|STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数提供特定的JDBC类型时,为空值指定JDBC类型。某些驱动需要指定列的JDBC类型,多数情况直接用一般类型即可,比如NULL、VARCHAR或OTHER。 | JdbcType常量.大多都为:NULL,VARCHARandOTHER | 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会返回一个空实例。请注意,它也适用于嵌套的结果集(i.e.collectioinandassociation)。(从3.4.2开始) | true|false | false |
logPrefix | 指定MyBatis增加到日志名称的前缀。 | 任何字符串 | Notset |
logImpl | 指定MyBatis所用日志的具体实现,未指定时将自动查找。 | SLF4J|LOG4J|LOG4J2|JDK_LOGGING|COMMONS_LOGGING|STDOUT_LOGGING|NO_LOGGING | Notset |
proxyFactory | 指定Mybatis创建具有延迟加载能力的对象所用到的代理工具。 | CGLIB|JAVASSIST | JAVASSIST(MyBatis3.3orabove) |
vfsImpl | 指定VFS的实现 | 自定义VFS的实现的类全限定名,以逗号分隔。 | Notset |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。为了使用该特性,你的工程必须采用Java8编译,并且加上-parameters选项。(从3.4.1开始) | true|false | true |
configurationFactory | 指定一个提供Configuration实例的类。这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。这个类必须包含一个签名方法staticConfigurationgetConfiguration().(从3.2.3版本开始) | 类型别名或者全类名. | Notset |
由于类的完全限定名称比较长,大量使用时十分不方便。MyBatis通过别名的方式来代表它,在MyBatis中别名是不区分大小写。别名又分为系统定义别名和自定义别名。
配置自定义别名:
使用注解配置别名:
@Alias("blog")
public class Blog {
...
}
系统自定义别名:
别名 | 映射的类型 |
---|---|
_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 |
在JDBC中,需要在PreparedStatement中处理预编译的SQL语句中的参数,执行完毕SQL后,通过ResultSet对象获得数据库中的数据,这些数据类型在MyBatis中通过typeHandler实现。在typeHandler中分为jdbcType和javaType。jdbcType定义数据库类型,javaType定义java类型。typeHandler的作用是承担jdbcType和javaType之间的相互转换。一般来说,系统定义的typeHandler就足够我们使用,我们还可以自定义typeHandler来处理我们需要满足的转换规则。
系统定义的typeHandler:
类型处理器 | Java类型 | JDBC类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean,boolean | 数据库兼容的BOOLEAN |
ByteTypeHandler | java.lang.Byte,byte | 数据库兼容的NUMERIC或BYTE |
ShortTypeHandler | java.lang.Short,short | 数据库兼容的NUMERIC或SHORTINTEGER |
IntegerTypeHandler | java.lang.Integer,int | 数据库兼容的NUMERIC或INTEGER |
LongTypeHandler | java.lang.Long,long | 数据库兼容的NUMERIC或LONGINTEGER |
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 | EnumerationType | VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引) |
EnumOrdinalTypeHandler | EnumerationType | 任何兼容的NUMERIC或DOUBLE类型,存储枚举的索引(而不是名称)。 |
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 | VARCHARorLONGVARCHAR |
JapaneseDateTypeHandler | java.time.chrono.JapaneseDate | DATE |
自定义typeHandler需要实现TypeHandler接口
public class MyTypeHandler implements TypeHandler {
// ...重写方法
}
配置自定义typeHandler:
使用包扫描和注解注册typeHandler
@MappedTypes(Integer.class)
@MappedJdbcTypes(jdbcType.VARCHAR)
public class MyTypeHandler implements TypeHandler {
// ...重写方法
}
使用自定义typeHandler
枚举typeHandler
大多数情况下,typeHandler因为枚举而使用,MyBatis定义了两个类作为枚举类型地支持,因为不常用,所以我们了解一下即可。分别是EnumOrdinalTypeHandler和EnumTypeHandler。其中,EnumOrdinalTypeHandler是按照MyBatis根据数组下标索引的方式进行匹配的,它要求数据库返回一个整数作为其下标,它会根据下标找到对应的枚举类型。 EnumTypeHandler会把使用的名称转换为对应的枚举,比如它根据数据库返回的字符串“MALE”进行Enum.valueOf(SexEnum.class,“MALE”)转换。
文件操作
MyBatis对数据的Blob的字段进行了支持,提供了一个BlobTypeHandler,还有ByteArrayTypeHanddler,只不过不太常用。因为一次性把大批量的数据加载到JVM中,会对服务器造成很大的压力,应该考虑采用文件流的形式。因为性能不佳,大型互联网网站会采用文件服务器的形式,能够对文件进行更为告诉的操作。
MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。MyBatis允许自定义ObjectFactory,可以继承ObjectFactory来实现,但是由于里面的自定义返回规则比较复杂且易出错,所以我们继承系统实现好的ObjectFactory即可。
public class MyObjectFactory extends DefaultObjectFactory {
// .....重写方法
}
XML配置:
插件是MyBatis中最为强大和灵活的组件,也是最为复杂、最难使用的组件。因为它覆盖了MyBatis底层对象的核心方法和属性,如果不熟悉MyBatis底层的构建和运行原理,请不要随意自定义使用。
MyBatis 允许使用插件来拦截的方法调用包括:
自定义插件:
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class MyPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return null;
}
@Override
public Object plugin(Object o) {
return null;
}
@Override
public void setProperties(Properties properties) {
}
}
XML配置:
运行环境主要用来配置数据库信息,可以配置多个数据库。主要分为两个配置元素transactionManager(事务管理器)和dataSource(数据库)。
在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):
JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
dataSource三种数据源及其属性:
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。
使用时,需要在映射器中加上databaseId
前面我们知道实现映射器常用的实现方式是声明一个接口并配合xml文件使用。映射器中的定义命名空间(namespace),命名空间对应的是一个接口的全路径。
在配置文件中我们要引入映射器,共有以下几种实现方式:
1. 使用相对于类路径的资源引用
2. 使用完全限定资源定位符(URL)
3. 使用映射器接口实现类的完全限定类名
4. 将包内的映射器接口实现全部注册为映射器