什么是 MyBatis ?
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
MyBatis是一个基于Java的持久层框架,是Apache下的一个顶级项目。当然,下面主要讲解的也是MyBatis的入门使用。在这里也只是我学习过程中的一个记录。毕竟网上对MyBatis介绍以及使用的文章太多太多了。
另外,学习MyBatis除了网上的文章或教程视频外,其过程我们不能脱离MyBatis的官方文档(传送门:MyBatis官方文档)。下面开始我们的MyBatis学习吧!!!
创建一个新的工程,导入MyBatis的jar包及相关依赖的jar包。(这里使用的是mybatis-3.4.6)下载地址:mybatis 3
为在使用MyBatis过程中看到MyBatis的执行日志(MyBatis默认使用log4j输出日志信息),我们先在项目的classpath下(这里我在项目的根目录创建了一个config目录,在config目录下)创建log4j.properties,内容如下:
# Global logging configuration
# 在开发环境下日志级别建议设置为DEBUG,生产环境设置成INFO或ERROR
log4j.rootLogger=DEBUG, stdout
# Console output
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
(1)创建MyBatis核心配置文件
在config目录(该目录在项目根目录下被创建)下,(实际上也是classpath)创建MyBatis的核心配置文件,该文件的名称和位置并不是固定的。在这里我们将该文件命名为SqlMapConfig.xml。
MyBatis的核心配置文件包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。
SqlMapConfig.xml,内容如下:
<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:///mydb_329?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
dataSource>
environment>
environments>
configuration>
这里采用的是名为mydb_329
的数据库。
(2)创建po类,po类作为MyBatis进行SQL映射使用,po类通常与数据表对应,User.java如下:(这里已经在数据库中事先准备好了mb_user
表,对应于该po类)
package com.wm103.po;
import java.util.Date;
/**
* Created by DreamBoy on 2018/4/9.
*/
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", address='" + address + '\'' +
'}';
}
}
(3)在config/sqlmap
目录中创建User.xml映射文件,该文件是主要用于配置输入参数同SQL的映射以及SQL操作结果同输出结果的映射关系,在映射文件中我们可以配置SQL语句。
在原始的iBatis中,习惯以xxx.xml命名,如 User.xml;在MyBatis中mapper代理开发(后续会讲解“什么是mapper代理开发”以及“如何实现mapper代理”等)映射文件名称则习惯以xxxMapper.xml名称,如 UserMapper.xml。
映射文件的基本内容如下:
<mapper namespace="user">
mapper>
在这里需要重点说明的是mapper
标签上的namespace
属性,即该属性用于对SQL进行分类化管理,不同的映射文件中设置的mapper
的namespace
不同。使用mapper代理方式开发,namespace
有着特殊的重要作用,后续将进行讲解。
(4)在MyBatis核心配置文件中(这里指的是SqlMapConfig.xml)引入映射文件,如下:
<mappers>
<mapper resource="sqlmap/User.xml"/>
mappers>
引入后,在java代码中使用的即是该核心配置文件的内容,通过核心配置文件,可以知道各映射文件的配置,从而进行对应的SQL操作。那么在实际编写CURD操作之前,我们有必要了解,MyBatis在java程序中,是“如何加载配置文件的”,以及“加载配置文件后我们又该如何获取到实现CURD的对象进行CURD操作的”等一系列问题。
那么根据以上说明,实际上我们所需做的步骤是:
1. 加载配置文件,创建会话工厂(会话工厂可采用单例模式进行实现);
2. 通过会话工厂,获取SqlSession对象;
3. 通过SqlSession对象操作数据库。
MyBatis的简单工具类 MyBatisUtil.java,如下:
package com.wm103.utils;
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.IOException;
import java.io.InputStream;
/**
* Created by DreamBoy on 2018/4/9.
*/
public class MyBatisUtil {
private final static SqlSessionFactory sqlSessionFactory;
static {
String resource = "SqlMapConfig.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
public static void closeSession(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
}
下面使用该工具类,实现CURD操作,为了方便案例的演示,创建一个测试类TestMyBatis,如下:
package com.wm103.test;
import com.wm103.po.User;
import com.wm103.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.Date;
import java.util.List;
/**
* Created by DreamBoy on 2018/4/9.
*/
public class TestMyBatis {
}
在该测试类内实现CURD操作。
(1)在User.xml映射文件中,配置SQL语句,如下:
<select id="findUserById" parameterType="int" resultType="com.wm103.po.User">
SELECT * FROM mb_user WHERE id=#{id}
select>
说明:
1. select标签用于标识该SQL语句实现的是查询操作;
2. id属性标识该映射文件中的SQL(在讲原理的时候,我们提到操作数据库前,会将SQL语句封装到一个叫MappedStatement对象中,因此这里的id我们也可以称之为statement的id)
3. parameterType属性指定输入参数的类型,这里指定为int类型;
4. SQL语句中的#{}表示一个占位符,接收的是输入参数的内容,如:#{id},其中id表示接收输入的参数,参数名称为id。对于简单类型而言,#{}中的参数名可以任意,而对于对象而言,#{}中的参数名需要对象的属性名,对于HashMap来说,#{}中的参数名则为map的key。
5. resultType属性指定输出结果的映射类型,确切地说是指单条记录所映射的java对象类型,这里将查询结果映射到User对象中。
(2)测试方法,如下:
@Test
public void findUserByIdTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
User user = sqlSession.selectOne("user.findUserById", 1);
System.out.println(user);
MyBatisUtil.closeSession(sqlSession);
}
说明:
通过SqlSession的方法操作数据库,这里使用的方法的参数:
1. 第一个参数:映射文件中的statement的id,即 映射文件的namesapce.statement的id,如user.findUserById;
2. 第二个参数:指定输入参数,与映射文件对应的配置所设置的parameterType属性值相匹配;
3. 方法的返回结果:与映射文件对应的配置所设置的resultType属性值相匹配。
(1)在User.xml映射文件中,配置SQL语句,如下:
<select id="findUserByName" parameterType="java.lang.String" resultType="com.wm103.po.User">
SELECT * FROM mb_user WHERE username LIKE '%${value}%'
select>
说明:
1. resultType属性在查询多条返回记录时,该属性值指的是单条记录所映射的java对象类型;
2. ${}表示将接收到的参数内容不加任何修饰的拼接在原有的SQL语句中,注意使用${}
拼接SQL可能将引起SQL注入的问题。${}
中,如果接收的输入参数为简单类型,那么拼接SQL语句时必须为${value}
。
(2)测试方法,如下:
@Test
public void findUserByNameTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
List list = sqlSession.selectList("user.findUserByName", "mb");
System.out.println(list);
MyBatisUtil.closeSession(sqlSession);
}
(1)在User.xml映射文件中,配置SQL语句,如下:
<insert id="insertUser" parameterType="com.wm103.po.User">
INSERT INTO mb_user(username, birthday, sex, address) value(#{username}, #{birthday}, #{sex}, #{address})
insert>
(2)测试方法,如下:
@Test
public void insertUserTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
User user = new User();
user.setUsername("mb_user03");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("广东广州");
sqlSession.insert("user.insertUser", user);
sqlSession.commit();
MyBatisUtil.closeSession(sqlSession);
}
有时在执行添加操作后,我们需要获取到刚被添加记录的主键的值。那么应如何实现呢?下面将分两个部分进行讲解,包括自增主键的获取、非自增主键的获取。以MySQL为例。
为获取自增主键的值,在映射文件中应做如下配置,如:
<insert id="insertUser" parameterType="com.wm103.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
INSERT INTO mb_user(username, birthday, sex, address) value(#{username}, #{birthday}, #{sex}, #{address})
insert>
说明:
1. selectKey标签用来执行额外操作,并将结果设置到输入参数值中。属性如下(摘录自官方文档):
属性 | 描述 |
---|---|
keyProperty | selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn | 匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
resultType | 结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。 |
order | 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。 |
statementType | 与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。 |
2. SELECT LAST_INSERT_ID()
:查询刚执行插入的记录的主键ID,配合insert
语句使用,在insert
之后调用。
使用MySQL的uuid()函数生成主键,需要修改表中id字段类型为string,且长度为35位。这种非自增主键的实现方式如下:
1. 首先通过uuid()查询到主键;
2. 将查询到的主键作为SQL语句中的insert的值;
3. 执行insert语句。
因此从这里我们也可以看出执行uuid()语句(即获取主键的操作)的顺序相对于insert语句之前执行。映射文件的配置如下:
<insert id="insertUser2" parameterType="com.wm103.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
SELECT uuid()
selectKey>
INSERT INTO mb_user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})
insert>
(1)在User.xml映射文件中,配置SQL语句,如下:
<delete id="deleteUser" parameterType="java.lang.Integer">
DELETE FROM mb_user WHERE id = #{id}
delete>
(2)测试方法,如下:
@Test
public void deleteUserTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
sqlSession.delete("user.deleteUser", 1);
sqlSession.commit();
MyBatisUtil.closeSession(sqlSession);
}
(1)在User.xml映射文件中,配置SQL语句,如下:
<update id="updateUser" parameterType="com.wm103.po.User">
UPDATE mb_user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
update>
(2)测试方法,如下:
@Test
public void updateUserTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
User user = new User();
user.setId(2);
user.setUsername("mb_user01");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("新地址");
sqlSession.update("user.updateUser", user);
sqlSession.commit();
MyBatisUtil.closeSession(sqlSession);
}
(1)在User.xml映射文件中,配置SQL语句,如下:
<update id="updateUserBySex" parameterType="com.wm103.po.User">
UPDATE mb_user SET username = #{username}, birthday = #{birthday}, address = #{address} WHERE sex = #{sex}
update>
(2)测试方法,如下:
@Test
public void updateUserBySexTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
User user = new User();
user.setUsername("mb_user");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("新地址23333");
sqlSession.update("user.updateUserBySex", user);
sqlSession.commit();
MyBatisUtil.closeSession(sqlSession);
}
#{}
和${}
#{}
表示一个占位符,接收输入参数,参数的类型可以是简单类型、pojo、HashMap。如果#{}
接收简单类型,则#{}
中可以写成value或其他名称,如#{value}
等;如果#{}
接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性....
的方法获取对象属性值;如果#{}
接收HashMap类型,则#{}
中为HashMap的key值。 ${}
则是一个拼接符号,会引起SQL注入,所以不建议使用。${}
接收输入参数,参数类型可以是简单类型、pojo、HashMap。如果接收${}
接收简单类型,则${}
必须写成${value}
;如果接收pojo或者HashMap则同#{}
的规则一致。selectOne
和selectList
selectOne
查询一条记录进行映射。查询一条记录时,也可以使用selectList
实现,只是使用selectList
后返回结果中List只有一个值,即最后需要的那一条查询记录。 selectList
查询出一个列表(多条记录)进行映射。查询结果不止一条记录时,不能使用selectOne
查询,否则将报如下错误:org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2
我们可以使用如下方法测试一下:
@Test
public void findUserByNameTestError() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
User user = sqlSession.selectOne("user.findUserByName", "mb");
System.out.println(user);
MyBatisUtil.closeSession(sqlSession);
}
对于SqlSessionFactory而言,我们可以采用单例模式对SqlSessionFactory进行管理,无需创建多个SqlSessionFactory对象,MyBatis同Spring整合后,我们将采用单例的方式创建SqlSessionFactory对象。
SqlSession是一个面向程序员的接口,它提供了许多操作数据库的方法。此处之外,需要特别注意的是,SqlSession是线程不安全的,在SqlSession的实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。因此SqlSession最佳应用场合是在方法体内,定义成局部变量使用。
MyBatis中开发dao的方法有两种,一种是原始的dao开发方法,需要我们程序员编写dao接口和dao实现类;两一种则为mapper代理方法,我们程序员只需编写mapper接口(相当于dao接口),除此之外,还需遵守一些规范。
(使用同上述案例相同的映射文件,即User.xml)
(1)首先编写dao接口,这里以User为例,即创建UserDao接口,如下:
package com.wm103.dao;
import com.wm103.po.User;
/**
* Created by DreamBoy on 2018/4/10.
*/
public interface UserDao {
User findUserById(int id) throws Exception;
void insertUser(User user) throws Exception;
void deleteUser(int id) throws Exception;
}
(2)创建UserDao的实现类UserDaoImpl,在实现类中需要注入SqlSessionFactory,用于获取SqlSession以实现数据库的操作,如下:(这里剩余了一些方法的具体实现)
package com.wm103.dao;
import com.wm103.po.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
/**
* Created by DreamBoy on 2018/4/10.
*/
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = this.sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.findUserById", id);
sqlSession.close();
return user;
}
@Override
public void insertUser(User user) throws Exception {
}
@Override
public void deleteUser(int id) throws Exception {
}
}
(3)编写测试类TestUserDaoImpl,如下:
package com.wm103.test;
import com.wm103.dao.UserDao;
import com.wm103.dao.UserDaoImpl;
import com.wm103.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by DreamBoy on 2018/4/10.
*/
public class TestUserDaoImpl {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findUserByIdTest() throws Exception {
UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
User user = userDao.findUserById(2);
System.out.println(user);
}
}
(1)创建新的映射文件,这里我们遵循mapper代理方式的命名规范,即UserMapper.xml。我们在config/mapper
目录下进行创建;
(2)在MyBatis核心配置文件中,引入映射文件:
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
(3)编写新的映射文件中的内容和mapper接口,要求如下:
1. 在映射文件中mapper的namespace属性的值应为mapper接口地址;
2. mapper.java接口中的方法名与mapper.xml中的statement的id一致;
3. mapper.java接口中的方法输入参数类型和mapper.xml中的statement的parameterType指定的类型一致;
4. mapper.java接口中的方法返回值类型和mapper.xml中的statement的resultType指定的类型一致(针对单条记录)。
映射文件 UserMapper.xml
<mapper namespace="com.wm103.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.wm103.po.User">
SELECT * FROM mb_user WHERE id=#{id}
select>
<select id="findUserByName" parameterType="java.lang.String" resultType="com.wm103.po.User">
SELECT * FROM mb_user WHERE username LIKE '%${value}%'
select>
<insert id="insertUser" parameterType="com.wm103.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
INSERT INTO mb_user(username, birthday, sex, address) value(#{username}, #{birthday}, #{sex}, #{address})
insert>
<insert id="insertUser2" parameterType="com.wm103.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
SELECT uuid()
selectKey>
INSERT INTO mb_user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})
insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
DELETE FROM mb_user WHERE id = #{id}
delete>
<update id="updateUser" parameterType="com.wm103.po.User">
UPDATE mb_user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
update>
<update id="updateUserBySex" parameterType="com.wm103.po.User">
UPDATE mb_user SET username = #{username}, birthday = #{birthday}, address = #{address} WHERE sex = #{sex}
update>
mapper>
mapper接口 UserMapper.java
package com.wm103.mapper;
import com.wm103.po.User;
import java.util.List;
/**
* Created by DreamBoy on 2018/4/10.
*/
public interface UserMapper {
User findUserById(int id) throws Exception;
List findUserByName(String name) throws Exception;
void insertUser(User user) throws Exception;
void deleteUser(int id) throws Exception;
}
(4)创建测试类,通过SqlSession根据mapper接口获取对应的代理对象,显示查询操作,无需我们mapper接口下的方法的具体逻辑。如下:
package com.wm103.test;
import com.wm103.mapper.UserMapper;
import com.wm103.po.User;
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.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Created by DreamBoy on 2018/4/10.
*/
public class TestUserMapper {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findUserByIdTest() throws Exception {
SqlSession sqlSession = this.sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(2);
sqlSession.close();
System.out.println(user);
}
@Test
public void findUserByNameTest() throws Exception {
SqlSession sqlSession = this.sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List list = userMapper.findUserByName("mb");
sqlSession.close();
System.out.println(list);
}
}
注:mapper接口方法参数只能设置一个,我们可以使用包装类型的pojo满足不同的业务需求。
通过SqlSession
获取的代理对象,针对查询操作而言,根据mapper接口定义的查询结果返回类型而调用selectOne
或selectList
方法。如果mapper方法定义的返回值类型为单个pojo对象(即非集合对象),则代理对象内部会使用selectOne
查询数据库;如果mapper方法定义的返回值类型为集合对象,则代理对象内部会使用selectList
查询数据库。(记住,如果使用selectOne
查询多条记录的话,要抛出异常哦!!!)
MyBatis的全局配置文件SqlMapConfig.xml,配置内容如下:
- properties 属性
- settings 设置
- typeAliases 类型别名
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境
|- environment 环境变量
|-- transactionManager 事务管理器
|-- dataSource 数据源
- databaseIdProvider 数据库厂商标识
- mappers 映射器
这里将不对每个标签进行一一讲解,而是对某些入门所需的标签进行说明。
(1)properties
使用properties可以加载外部的配置文件,并使用配置文件中的配置项。如:在config目录下,我们可以定义额外的配置文件,用来保存数据库的设置,如下:
config.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mydb_329?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=
在核心配置文件SqlMapConfig.xml中加载该配置文件,并采用${}
的方式使用该配置文件的配置,如下:
<configuration>
<properties resource="config.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
environments>
<mappers>
<package name="com.wm103.mapper"/>
mappers>
configuration>
这样做的好处是,将项目中一些重要的配置,如数据库配置,进行统一管理,也可以共享配置,有利于后续的维护。
除了加载配置文件的作用后,properties内部可以使用property子标签配置属性,如:
<properties resource="config.properties">
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
properties>
如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
最后读取作为方法参数传递的属性,并覆盖已读取的同名属性(即在创建SqlSessionFactory时传入Properties对象)。
因此,建议只采用加载外部配置文件的方式,将属性值定义在该文件中。
此外,值得注意的是,如果配置文件属性名同映射文件中SQL传入的参数对象的属性同名的话,在执行SQL语句时传入的参数对象的属性的值将为配置文件中同名的属性的值,而非statement传入的对象的属性值。如:
config.properties 做如下设置:
username=root
在映射文件中,如UserMapper.xml中:
"updateUserByUsername" parameterType="com.wm103.po.User">
UPDATE mb_user SET birthday = #{birthday}, address = #{address} WHERE username LIKE '%${username}%'
这时使用该statement,传入User对象,以username属性作为where条件参数时,就会发现执行数据库操作时所执行的SQL语句并非同我们预想的一样。${username}
很意外地使用了config.properties
文件中username
属性的值,而非我们传入的user对象的值。如:
@Test
public void updateUserByUsernameTest() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
User user = new User();
user.setUsername("mb");
user.setBirthday(new Date());
user.setAddress("新地址23333");
sqlSession.update("user.updateUserByUsername", user);
sqlSession.commit();
MyBatisUtil.closeSession(sqlSession);
}
运行结果后,我们发现执行的SQL语句为:
UPDATE mb_user SET birthday = ?, address = ? WHERE username LIKE '%root%'
因此,建议在properties文件中定义的属性名要有一定的特殊性。
(2)settings(配置)
MyBatis全局配置参数,该设置将会影响MyBatis的运行行为,如是否开启延迟加载、缓存配置等。这里先不做过多讲解,具体可参考官方文档。
(3)typeAliases(类型别名)
在映射文件中,我们可能需要配置输入映射(parameterType)或输出映射(resultType),而输入映射或输出映射为对象类型的话,那么则需要配置该对象的全路径。如果存在过多的相同配置的映射类型的话,实际上将不方便开发,因此,可以在核心配置文件中使用typeAliases
标签定义别名,后续映射类型使用定义的别名。
在MyBatis中默认支持了许多别名,如:java.lang.Integer
别名为int
。也因为如此,我们在映射文件中,可以使用int
作为输入映射类型或输出映射类型。如:
<select id="findUserById" parameterType="int" resultType="com.wm103.po.User">
SELECT * FROM mb_user WHERE id=#{id}
select>
那么如何自定义别名呢?自定义别名的方式有两种:一种是单个定义别名;另一种是批量定义别名(这也是一种常用的方式)。
单个定义别名,如下:
<typeAliases>
<typeAlias type="com.wm103.po.User" alias="user"/>
typeAliases>
做如上定义后,我们可以直接使用user
作为输入映射或输出映射的映射类型。
批量定义别名,通过指定包名,MyBatis会自动扫描包中的po类,自动定义别名,而自定定义出来的别名是类名或首字母小写的类名,如User或user均可作为别名引用。如下:
<typeAliases>
<package name="com.wm103.po"/>
typeAliases>
(4)mappers(映射配置)
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
1. mapper接口名同对应的映射文件的名称保持一致;
2. mapper接口和对应的映射文件在同一目录中;
3. 采用的是mapper代理方式
设置批量加载mapper方式,如下:
<mappers>
<mapper resource="sqlmap/User.xml"/>
<package name="com.wm103.mapper"/>
mappers>
属性配置元素详述