- MyBatis第一天
- 1. 简介
- 1.1 什么是 MyBatis
- 1.2 MyBatis发展历史
- 1.3 MyBatis的特点
- 1.4 如何获取
- 2. 入门
- 2.1 环境准备
- 2.1.1 准备一张表
- 2.2 创建一个工程
- 2.3 添加依赖
- 2.2 编写实体类
- 2.3 编写MyBatis全局配置文件
- 2.4 编写Dao接口类
- 2.5 编写MyBatis映射文件
- 2.6 编写测试
- 3. 源码分析
- 3.1 SqlSessionFactory
- 3.2 SqlSession
- 4. 实现CRUD
- 4.1 在接口中添加方法
- 4.2 修改映射文件:
- 4.3 编写测试
- 4.3.1 插入
- 4.3.2 更新
- 4.3.3 根据ID查询
- 4.3.4 多条件查询
- 4.3.5 删除
- 5. 配置文件
- 5.1 properties
- 5.2 settings
- 5.3 typeAliases
- 5.3.1 typeAlias
- 5.3.2 package
- 5.3.3 @Alias
- 5.4 typeHandlers
- 5.4.1 自定义类型转换器
- 5.4.2 配置自定义类型转换器
- 5.5 environments
- 5.5.1 transactionManager
- 5.5.2 dataSource
- 5.6 databaseIdProvider
- 5.6.1 配置
- 5.6.2 使用
- 5.7 mappers
- 5.7.1 逐个注册
- 5.7.2 接口名注册
- 5.7.3 基于注解配置
- 5.7.4 批量注册
MyBatis的官网是:https://mybatis.org/mybatis-3/zh/index.html
目前 MyBatis的版本为 3.5.9
1.1 什么是 MyBatisMyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
简单的说:MyBatis简化了我们对 JDBC 的 *** 作。
1.2 MyBatis发展历史MyBatis源自于 Apache 的一个开源项目 iBatis,2010年6月时这个项目由 Apache Software Foundation 迁移到了 Google Code,这些开发团队也就跟着迁移到了 Google Code 旗下。iBatis 就在 3.x 时正式更名为 MyBatis,并且把代码托管到了 GitHub。
iBatis 这名称来源于 “internet” 和 “abatis” 的组合,是一个基于 Java 的特久层框架。
1.3 MyBatis的特点1.MyBatis是一个半自动化的持久层框架
2.开发人员可以自己编写SQL语句来实现优化
3.在MyBatis中,SQL和Java代码是分开,边界清晰
1.4 如何获取在浏览器地址栏中输入MyBatis 的官网地址(https://github.com/mybaits/mybatis-3/releases),然后就可以下载。
或者使用 Maven 的坐标来进行项目的依赖添加。
2. 入门 2.1 环境准备 2.1.1 准备一张表create database if not exists mydb;
use mydb;
create table t_department
(
did int auto_increment
primary key,
dname varchar(100) not null,
description varchar(200) null,
manager_id int null
);
2.2 创建一个工程
在 IDEA 中,我们还在 JavaWeb 这个空工程下创建的 mybatis-one 模块。
2.3 添加依赖在项目的 pom.xml 文件中添加如下依赖。
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.9version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.49version>
dependency>
另外还可以把 lombok 添加到 pom.xml 文件中
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
<scope>providedscope>
dependency>
还可以添加一个日志依赖到项目中,如 logback
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.10version>
dependency>
还需要在项目的资源目录下创建 logback 的配置文件。
logback.xml
<configuration scan="true" scanPeriod="60 second" debug="false">
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger{0} %msg%nPattern>
<charset>UTF-8charset>
encoder>
appender>
<logger name="java.sql">
<level value="debug" />
logger>
<logger name="org.apache.ibatis">
<level value="info" />
logger>
<root level="DEBUG">
<appender-ref ref="Console" />
root>
configuration>
完整内容:
<configuration scan="true" scanPeriod="60 second" debug="false">
<property name="LOG_FILE_PATH" value="${catalina.base}/logs" />
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger{0} %msg%nPattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE_PATH}/mybatis.logfile>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFOlevel>
filter>
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger{0} %msg%nPattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>mybatis.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>30maxHistory>
<TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
TimeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
appender>
<logger name="java.sql">
<level value="debug" />
logger>
<logger name="org.apache.ibatis">
<level value="info" />
logger>
<root level="DEBUG">
<appender-ref ref="Console" />
<appender-ref ref="RollingFile" />
root>
configuration>
2.2 编写实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Department {
private Integer did;
private String dname;
private String description;
}
2.3 编写MyBatis全局配置文件
在项目的资源目录(resources)中创建 mybatis-config.xml 文件
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.72.71:3306/mydb?useSSL=false&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
configuration>
2.4 编写Dao接口类
package com.xianopeng.mapper;
import com.xianopeng.entity.Department;
import java.util.List;
/**
* Dao接口类
*/
public interface DepartmentMapper {
// 查询全部
List<Department> selectDepartments();
}
2.5 编写MyBatis映射文件在 MyBatis 中,一般定义 Dao 层为 mapper 层,而 XxxDao 定义为 XxxMapper。它们都是表示 Dao 层,只是命名不同而已。
在 MyBatis 中,通过映射文件来实现在 Jdbc 中的接口实现类的功能。
我们还是把这个文件放到资源目录下。文件的结构还是从官网上去取。一般定义为接口的名称.xml。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xianopeng.mapper.DepartmentMapper">
<select id="selectDepartments" resultType="com.xianopeng.entity.Department">
select * from t_department
select>
mapper>
2.6 编写测试配置说明:
- mapper:映射配置文件的根节点
- namespace:这个属性用于指定接口类所在的完整路径
- select:它是用于定义查询的标签,对应查询方法
- id:它用于与接口中的某个方法名称一致
- resultType:查询后的返回结果类型,需要写全限定名
1)把映射文件注册到全局配置文件中
<mappers>
<mapper resource="DepartmentMapper.xml" />
mappers>
在 mybatis-config.xml 文件中添加如上的配置,让映射文件注册到全局配置文件中,mappers 标签与 environments 标签平级。
2)编写测试类
package com.xianopeng.test;
import com.xianopeng.entity.Department;
import com.xianopeng.mapper.DepartmentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
/**
* 测试类
*/
public class MytatisTest {
public static void main(String[] args) throws Exception {
// 1. 创建 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 创建 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 创建 Mapper 对象
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
// 4. 执行方法
List<Department> departments = mapper.selectDepartments();
// 5. 处理结果
departments.forEach((department) -> {
System.out.println(department.getDid() + "\t" + department.getDname());
});
// 6. 关闭资源
sqlSession.close();
}
}
至此,我们已经成功的使用 MyBatis。
3. 源码分析在MyBatis中主要的类有以下几个:
- Configuation:将 MyBatis 配置文件的信息保存在这个类中
- SqlSessionFactory:解析 Configuration类中的配置信息,获取SqlSession对象
- SqlSession:负责和数据库进行交互,完成CRUD *** 作
- Executor:是MyBatis的高度核心,负责SQL的生成
- StatementHandler:封装了 JDBC 的 statement *** 作
- ParameterHanlder:负责完成 JavaType 到 jdbcType 的转换
- ResultSetHandler:负责完成结果集到 JavaBean 对象的转换
- MappedStatement:代表一个 select|insert|update|delete元素
- SqlSource:根据传入的 ParameterObject 来生成 SQL
- BundSQL:包含 SQL 和参数信息
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
在这个接口中定义一系列获取 SqlSession 的方法。
这个接口是通过 SqlSessionFactoryBuilder 类中的 build 方法来构建的。
在这个类中,定义了很多 build 的重载方法,来根据不同的条件来构建 SqlSessionFactory 接口。
我们使用的是如下方法:
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
这个方法会调用下面的方法:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
}
}
return var5;
}
在这个方法中,我们发现是使用 XMLConfigBuilder 类来读取配置文件的。
//....
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
// .............
在这个方法中使用的是 XPathParser 类
//.......
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
this.commonConstructor(validation, variables, entityResolver);
this.document = this.createDocument(new InputSource(inputStream));
}
//......
从上面的方法发现它使用了 new InputSource(inputStream) 对象
//........
public InputSource (InputStream byteStream)
{
setByteStream(byteStream);
}
//...............
public void setByteStream (InputStream byteStream)
{
this.byteStream = byteStream;
}
//........
这个类中把我们传过来的配置文件的字节码数据赋给 byteStream 成员。
接下来我们来看 XPathParser 类中的 this.createDocument(InputSource source) 方法
private Document createDocument(InputSource inputSource) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
factory.setValidating(this.validation);
factory.setNamespaceAware(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(this.entityResolver);
builder.setErrorHandler(new ErrorHandler() {
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
public void warning(SAXParseException exception) throws SAXException {
}
});
return builder.parse(inputSource);
} catch (Exception var4) {
throw new BuilderException("Error creating document instance. Cause: " + var4, var4);
}
}
在这个方法中,有一个关键的代码:
return builder.parse(inputSource);
这个就去是在 DocumentBuilder.java 文件中的一个内部的抽像方法。
public abstract Document parse(InputSource is)
throws SAXException, IOException;
它的具体实现在 DocumentBuilderImpl.java类中
public Document parse(InputSource is) throws SAXException, IOException {
if (is == null) {
throw new IllegalArgumentException(
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
"jaxp-null-input-source", null));
}
if (fSchemaValidator != null) {
if (fSchemaValidationManager != null) {
fSchemaValidationManager.reset();
fUnparsedEntityHandler.reset();
}
resetSchemaValidator();
}
domParser.parse(is);
Document doc = domParser.getDocument();
domParser.dropDocumentReferences();
return doc;
}
在这个方法中通过 domParser.parse(is);
来解析,实现代码如下:(DOMParser.java)
public void parse(InputSource inputSource)
throws SAXException, IOException {
// parse document
try {
XMLInputSource xmlInputSource =
new XMLInputSource(inputSource.getPublicId(),
inputSource.getSystemId(),
null, false);
xmlInputSource.setByteStream(inputSource.getByteStream());
xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
xmlInputSource.setEncoding(inputSource.getEncoding());
parse(xmlInputSource);
}
//...
核心代码为:parse(xmlInputSource);
/**
* parse
*
* @param inputSource
*
* @exception XNIException
* @exception java.io.IOException
*/
public void parse(XMLInputSource inputSource)
throws XNIException, IOException {
// null indicates that the parser is called directly, initialize them
if (securityManager == null) {
securityManager = new XMLSecurityManager(true);
fConfiguration.setProperty(Constants.SECURITY_MANAGER, securityManager);
}
if (securityPropertyManager == null) {
securityPropertyManager = new XMLSecurityPropertyManager();
fConfiguration.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager);
}
reset();
fConfiguration.parse(inputSource);
}
3.2 SqlSession通过SqlSessionFactoryBuiler 对象的 build() 方法为入口来解析 mybatis-config.xml 文件,把这个文件中的信息保存到 Configuration 对象中,并且创建 SqlSessionFactory 对象。
我们点击
public interface SqlSessionFactory {
SqlSession openSession();
}
进入到 DefaultSqlSessionFactory.java 类中
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
在这个方法中,创建了 Executor 对象,最后返回 DefaultSqlSession 对象,在这个类中提供了 *** 作数据库的方法。这些方法都最后使用 。
4. 实现CRUD 4.1 在接口中添加方法public interface DepartmentMapper {
// 插入
void insert(Department department);
// 更新
void update(Department department);
// 删除
void delete(Integer did);
// 查询全部
List<Department> selectDepartments();
// 根据id查
Department select(Integer did);
List<Department> selectByCondition(Integer did, String dname);
}
4.2 修改映射文件:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xianopeng.mapper.DepartmentMapper">
<insert id="insert" parameterType="com.xianopeng.entity.Department">
insert into t_deparment(dname,description) values(#{dname}, #{description})
insert>
<update id="update" parameterType="com.xianopeng.entity.Department">
update t_department set dname=#{dname},description=#{description} where did=#{did}
update>
<delete id="delete">
delete from t_deparment where did=#{did}
delete>
<select id="selectDepartments" resultType="com.xianopeng.entity.Department">
select * from t_department
select>
<select id="select" parameterType="int" resultType="com.xianopeng.entity.Department">
select * from t_department where did=#{did}
select>
<select id="selectByCondition" parameterType="map" resultType="com.xianopeng.entity.Department">
select * from t_department where did=#{did} and dname=#{dname}
select>
mapper>
4.3 编写测试
我们使用 junit 来编写测试,因此我们要把 Junit 的依赖添加到项目中。
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
编写测试:
4.3.1 插入package com.xianopeng.test;
import com.xianopeng.entity.Department;
import com.xianopeng.mapper.DepartmentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* 测试
*/
public class MyBatisCRUDTest {
private SqlSession sqlSession;
// 插入
@Test
public void testInsert() {
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
mapper.insert(new Department().setDname("市场部").setDescription("扩展业务的部门"));
// 提交事务
sqlSession.commit();
}
@Before
public void init() {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
@After
public void destroy() {
sqlSession.close();
}
}
4.3.2 更新
// 更新
@Test
public void testUpdate() {
try {
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
mapper.update(new Department().setDid(5).setDname("市场部").setDescription("给公司创收的部门"));
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
}
}
4.3.3 根据ID查询
@Test
public void testSelect() {
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
Department department = mapper.select(5);
System.out.println(department);
}
4.3.4 多条件查询
// 多条件查询
@Test
public void testSelectByCondition() {
Map<String, Object> map = new HashMap<>();
map.put("did", 5);
map.put("dname", "市场部");
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
List<Department> departments = mapper.selectByCondition(map);
departments.forEach((department) -> {
System.out.println(department.getDid() + "\t" + department.getDname());
});
}
4.3.5 删除
@Test
public void testDelete() {
try {
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
mapper.delete(5);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
}
}
5. 配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
- properties:用于定义外部数据库连接信息
- settings:设置全局的参数,用于优化 MyBatis 框架
- typeAliases:用于指定别名
- typeHandlers:用于定义或配置类型处理器
- objectFactory:对象工厂
- plugins:用于配置 MyBatis 的插件功能
- environments:用于运行环境
- databaseProvider:用于定义数据库厂商的标识,便于切换数据库
- mappers:用于注册映射文件
我们在项目的资源目录中创建 db.properties 文件,在这个文件中定义数据库连接信息。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.72.71:3306/mydb?useSSL=false&characterEncoding=utf8
username=root
password=123456
接下来在主配置文件中使用 properties 标签来把我们编写好的连接数据库信息的文件引用。
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties" />
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="DepartmentMapper.xml" />
mappers>
configuration>
通过 properties 标签来引用外部的数据库连接信息文件,然后在文件中需要使用的地方通过 ${key} 方式来引用。
5.2 settings这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
它的具体配置信息参考官网的内容:https://mybatis.org/mybatis-3/zh/configuration.html#settings
在官网的 settings 项目最后,有一个完整推荐配置:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
settings>
5.3 typeAliases
这个标签是用于给我们的 Java 对象指定别名,从而让我们的代码更加简洁。
5.3.1 typeAlias对于它的配置,我们可以按如下的方式来进行:
<typeAliases>
<typeAlias type="com.xianopeng.entity.Department" alias="Department"/>
typeAliases>
这种方式指定好后,我们就可以修改映射文件:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xianopeng.mapper.DepartmentMapper">
<insert id="insert" parameterType="Department">
insert into t_department(dname,description) values(#{dname}, #{description})
insert>
<update id="update" parameterType="Department">
update t_department set dname=#{dname},description=#{description} where did=#{did}
update>
<delete id="delete">
delete from t_department where did=#{did}
delete>
<select id="selectDepartments" resultType="Department">
select * from t_department
select>
<select id="select" parameterType="int" resultType="Department">
select * from t_department where did=#{did}
select>
<select id="selectByCondition" parameterType="map" resultType="Department">
select * from t_department where did=#{did} and dname=#{dname}
select>
mapper>
此时,我们在返回类型或参数类型中就可以使用定义好的别名来指定。
使用这种方式定义好别后,确实可以来简化映射文件的编写,但是这种方式有一个不好的方是:如果有多个映射文件(实体),我们需要定义多个别名。
<typeAliases>
<typeAlias type="com.xianopeng.entity.Department" alias="Department"/>
<typeAlias type="com.xianopeng.entity.Employee" alias="Employee"/>
<typeAlias type="com.xianopeng.entity.User" alias="User"/>
<typeAlias type="com.xianopeng.entity.Person" alias="Person"/>
.........
typeAliases>
使用这种方式后会让我们配置文件变得臃肿。
5.3.2 package在 MyBatis 中,为了解决这个问题,它提供另外一种配置方式。
<typeAliases>
<package name="com.xianopeng.entity"/>
typeAliases>
使用 package 子标签来定义,我们此时只需要定义实体所在的包名即可。
使用这种方式来配置别名,可以让配置文件变得非常干净,同时也可以让映射文件变得简洁。但它的限制是别名只能使用类名来使用。
5.3.3 @Alias每一个在包
com.xianopeng.entity
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如com.xianopeng.entity.Author
的别名为author
;若有注解,则别名为其注解值。
除了上述两种方式个,还可以在实体类上使用 @Alias 注解来进行别名的配置
@Alias("author")
public class Author {
...
}
这时这个类的别名就是 author。
5.4 typeHandlersMyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。
MyBatis中给我们提供了很多的类型处理器,如果这些类型处理器不能满足我们的开发需要,我们还可以去重写这些类型处理器, 或者自定义类型处理器。
自定义类型处理器是 BaseTypeHandler 子类,而 BaseTypeHandler 类继承了 TypeReference 类并实现了 TypeHandler。
TypeHandler是一个接口,在这个接口中定义了参数的设置方法和获取结果集的方法。
TypeReference 是一个抽像类,它定义了如何获取类的真实的泛型类型。
5.4.1 自定义类型转换器package com.xianopeng.type;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 自定义类型转换器,它需要继承 BaseTypeHandler 的抽像类
*/
public class CustomTypeHandler extends BaseTypeHandler<String> {
// 根据参数的位置和值来设置 SQL 中的参数
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, s);
}
// 根据字段名称来获取它的值
@Override
public String getNullableResult(ResultSet resultSet, String s) throws SQLException {
return resultSet.getString(s);
}
// 根据字段的索引获取它的值
@Override
public String getNullableResult(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString(i);
}
// 获取存储过程的值
@Override
public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return callableStatement.getString(i);
}
}
5.4.2 配置自定义类型转换器
把自定义的类型转换器在 MyBatis 的配置文件中使用 typeHandlers 标签来进行配置。
<typeHandlers>
<typeHandler handler="com.xianopeng.type.CustomTypeHandler"/>
typeHandlers>
当然,也可以使用 package 子标签来指定自定义类型转换器所在的包名,这样就可以批量配置。
<typeHandlers>
<package name="com.xianopeng.type"/>
typeHandlers>
5.5 environments
在 MyBatis 中可以配置多个运行环境,通过指定 environment 标签来实现
<environments default="production">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
<environment id="production">
<transactionManager type="JDBC">
<property name="..." value="..."/>
transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
5.5.1 transactionManager注意:
在 environments 标签中的 default 属性的值,必须与其子标签 environment 中的某一个配置的 id 属性的值相同,表示使用这个环境。
transactionManager:这个标签是用于配置事务管理的方式,默认使用 JDBC 事务。
dataSource:用于配置MyBatis 所使用的数据源信息。
在 MyBatis 中提供了两种事务管理器:
- JDBC:使用 JDBC 原生的事务来进行管理,事务提交和回滚机制,依赖于从数据源得到的连接来管理事务范围,也就是 JdbcTransactionFactory 的别名。
- MANAGED:这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,它是 ManagedTransactionFactory 的别名。
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
在 MyBatis 中有三种内建的数据源类型(也就是 type=“[UNPOOLED|POOLED|JNDI]”):
- UNPOOLED:这个数据源的实现会每次请求时打开和关闭连接,实际上就是不使用连接池技术。
- POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求,实际上就是使用连接池技术。
- JNDI:这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。它也是利用连接池技术,但是它的可移置性非常差。
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId
属性。
在 mybatis-config.xml 文件中配置 databaseIdProvider 标签来指定数据厂商。
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle" />
databaseIdProvider>
5.6.2 使用
在映射文件中通过 databaseId 来引用。
<select id="selectDepartments" resultType="Department" databaseId="mysql">
select * from t_department
select>
5.7 mappers
它是用于注册我们的映射文件,使用有以下几种方式:
5.7.1 逐个注册<mappers>
<mapper resource="DepartmentMapper.xml" />
<mapper resource="EmployeeMapper.xml" />
mappers>
有多少个映射文件,我们就需要在 mappers 标签中使用多少个 mapper 子标签来注册。这种方式可行,但是会让配置文件变得臃肿。
5.7.2 接口名注册要实现接口名注册我们需要把接口的地址放到 mappers 标签中,然后通过 class 属性来指定。
<mappers>
<mapper class="com.xianopeng.mapper.EmployeeMapper"/>
<mapper class="com.xianopeng.mapper.DepartmentMapper"/>
mappers>
要使用这种方式,我们需要把映射文件和接口类放在同一个目录下。
另外,在 IDEA 中,默认情况下,Maven 工程是不会把除了 resources 目录下的资源文件编译到类路径下外,其它目录下的 xml 文件、properties 文件等是不会编译到类路径下的。要想让它进行编译,我们需要在 pom.xml 文件中添加如下的配置。
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.xmlinclude>
<include>**/*.propertiesinclude>
includes>
resource>
resources>
build>
5.7.3 基于注解配置
我们要想使用注解配置,我们就需要在接口的方法中添加注解,然后再 mappers 标签中使用类名来注册。
5.7.4 批量注册<mappers>
<package name="com.xianopeng.mapper" />
mappers>
使用这种方式,也是需要把映射文件和接口类放到同一个目录中。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)