Mybatis的官方网址:http:// https://mybatis.org/mybatis-3/zh/index.html
一、Mybatis概述
Mybatis是一个优秀的基于java的持久化框架,它内部封装了jdbc,是开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁琐过程。
mybatis通过XML或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终地sql语句,最后由mybatis框架执行sql并将结果映射为java对象返回。
采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。
Mybatis的特点:
(1)简单易学:本身很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。
(2)灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
(3)解除sql与程序代码的耦合:提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易于维护。
(4)提供映射标签,支持对象与数据库的orm字段关系映射
(5)提供对象关系映射标签,支持对象关系组件维护
(6)提供xml标签,支持编写动态sql
(7)支持数据缓存和注解开发
二、Mybatis环境搭建
(1)前期准备
1、 创建数据库
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT
NULL,
`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT
NULL,
`nickname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT
NULL,
`age` int(11) DEFAULT NULL,
`birthday` date DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE =
utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
2、创建maven Java项目
3、导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
(2)搭建项目环境
1、编写User实体类
package cn.offcn.entity;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private String nickname;
private Integer age;
private Date birthday;
//生成getter和setter方法
}
2、编写持久层User接口
com.offcn.dao
public interface UserDao {
/*添加用户*/
int insert(User user);
}
3、编写持久层User接口映射文件UserDao.xml
resources com/offcn/dao
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--映射
namespace:与对应接口的全限定名一致:接口的包名.类名
-->
<mapper namespace="com.offcn.dao.UserDao">
<!--添加
id:与接口的方法名一致
传的值: #{变量名:与接口的方法参数有关
username与password就是接口方法传来的User对象中的两个属性名
}
getUserName() getPassword()
-->
<insert id="insert">
insert into user(username,password)values(#{username},#{password})
</insert>
</mapper>
4、编写mybatis主配置文件SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置 mybatis的环境 -->
<environments default="development">
<!-- 配置环境 -->
<environment id="development">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源【连接池】-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 注册UserDao接品映射文件位置 -->
<!--加载映射文件
resource:映射文件所在的classpath下路径-->
<mappers>
<mapper resource="com/offcn/dao/UserDao.xml"></mapper>
</mappers>
</configuration>
三、Mybatis入门
测试代码
@Test
public void add()throws Exception{
//读取mybati的核心配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
//MyBatis框架的核心对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建一个SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//调用接口方法
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user=new User("xiaoyueyue","123");
mapper.insert(user);
//提交事务
sqlSession.commit();
//释放连接资源
sqlSession.close();
}
四、Myabtis执行原理分析
(1)配置文件分析
核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置 mybatis 的环境 -->
<environments default="development">
<!-- 配置的环境 -->
<environment id="development">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源【连接池)】-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis001"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 注册UserDao接品映射文件位置 -->
<mappers>
<mapper resource="cn/offcn/dao/UserDao.xml"/>
</mappers>
</configuration>
核心配置文件参数详解:
1、environment标签中的id属性值必须和environment标签中的default属性一致。
2、事务管理器:
第一种采用JDBC事务类型,直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事物作用域。
第二种采用MANAGED事务类型,它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE应用服务器的上下文)。默认情况下他会关闭连接。然而一些容器并不希望连接被关闭,因此需要将closeConnection属性设置为false来阻止默认的关闭行为。例如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
3、数据源(datasource)
dataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源。大多数Mybatis应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(Type="[UNPOOLED|POOLED|JNDI]")
UNPOOLED:这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对于那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
POOLED:这种数据源的实现利用“池”的概念将JDBC连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。这些处理方式很流行,能使并发Web应用快速响应请求
JNDI:这个数据源实现是为了能在如EJB或应用服务器这类容器中使用,容器可以几种或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。
4、mapper中的resource属性用于指定映射文件的位置。mapper中多个属性可以描述映射文件,分别为:
映射文件:
<mapper namespace="cn.offcn.dao.UserDao">
<!--配置查询的sql语句-->
<select id="queryAllUsers" resultType="cn.offcn.entity.User">
select * from user
</select>
</mapper>
映射文件参数详解:
(1)namespace必须为接口的完全限定名(即包名+类名的格式)
(2)select标签中的id必须和接口声明的方法同名。
(3)如果接口中方法有返回值,resultType必须跟方法返回值一致并采用返回值的完全限定名来表示。
(2)底层源码分析
(3)执行原理图
五、Mybatis基于代理Dao实现CRUD操作
(一)数据保存
1、定义数据添加的接口方法addUser
public class UserDao{
/**
新增添加用户方法
*/
public void addUser(User user);
}
2、配置文件中配置对应的sql
<insert id="addUser" parameterType="cn.offcn.entity.User">
insert into user(name,gender,age,birthday) values (#{name},#{gender},#
{age},#{birthday})
</insert>
#{}为mybatis的占位符,如果方法中传递的参数为实体类类型,#{实体类属性}
3、添加测试方法
@Test
public void testAddUser() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
//创建User对象
User user = new User("何晓","男",22,new Date());
//调用addUser方法进行保存
userDao.addUser(user);
//关闭连接
MyBatisUtils.close(session);
}
(二)数据更新
1、定义数据添加的接口方法updateUser
/**
* 更新user对象
* @param user
*/
public void updateUser(User user);
2、配置文件中配置对应的sql
<update id="updateUser" parameterType="cn.offcn.entity.User">
update user set name=#{name},gender=#{gender},age=#{age},birthday=#
{birthday} where id=#{id}
</update>
3、添加测试方法
@Test
public void testUpdateUser() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
//创建User对象
User user=new User("何晓飞","女",21,new Date());
//指定要更新id
user.setId(1);
//调用updateUser方法进行修改
userDao.updateUser(user);
//关闭连接
MyBatisUtils.close(session);
}
(三)数据删除
1、定义数据添加的接口方法deleteUser
/**
* 根据id删除指定user
* @param id
*/
public void deleteUser(Integer id);
2、配置文件中配置对应的sql
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
3、添加测试方法
@Test
public void testDeleteUser() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
//调用deleteUser方法进行删除
userDao.deleteUser(2);
//关闭连接
MyBatisUtils.close(session);
}
(四)#{}和${}的区别
1、#{}是预编译处理,${}是字符串替换
2、Mybatis在处理${}时,就是把${}替换成变量的值
3、Mybatis在处理${}时,会将sql中的#{}替换为?号,调用preparedStatement的set方法来赋值。
4、使用#{}可以有效的防止SQL注入,提高系统安全性。
(五)Mybatis实现模糊查询
模糊查询在我们开发中是一项必不可缺少的重要内容。对于我们mybatis实现模糊查询有三种方式,以下具体的实现步骤:
1、添加模糊查询的接口方法likeSearchUsers
/**
* 根据昵称进行模糊查询
*/
List<User>selectByLikeNickname(String str);
2、配置接口方法对应的sql文件
(1)配置占位符方式#{}
<select id="selectByLikeNickname" resultType="com.offcn.entity.User">
select * from user where nickname like #{str}
</select>
(2)配置拼接字符串方式${}
<select id="selectByLikeNickname" resultType="com.offcn.entity.User">
select * from user where nickname like ${str}
</select>
(3)配置mysql函数方式concat
<select id="selectByLikeNickname" resultType="com.offcn.entity.User">
select * from user where nickname like CONCAT("%",#{str},"%")
</select>
3、模糊查询测试
@Test
public void like(){
// select * from user where nickname like '%胖% or 1=1 --';
SqlSessionFactory sqlSessionFactory= MyBatisUtil.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
//1.List<User> list = mapper.selectByLikeNickname("%胖%");
//2.List<User> list = mapper.selectByLikeNickname("'%胖%' or 1=1 -- ");
//3
List<User> list = mapper.selectByLikeNickname("胖");
System.out.println(list);
//CONCAT(a,b,c)==>abc
}
六、Mybatis的参数处理
1、parameterType配置参数
(1)参数的使用说明
SQL语句传参,使用标签的parameterType属性来设定。该属性的取值可以是基本类型,引用类型,还可以是实体类类型(POJO类)。同时也可用以使用实体类的包装类。
(2)参数配置的注意事项
基本类型和String可以直接写类型名称也可以使用包名.类名的方式,例如java.lang.string。实体类类型,目前我们只能使用全限定类名。
mybatis在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。
别名 | 映射类型 |
_byte | byte |
_long | long |
_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 |
deciaml | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | Listg |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
这些都是支持的默认别名,我们可以从源码角度来看它们分别都是如何定义出来的。
2、传递pojo包装对象
开发中通过pojo传递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其他查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递参数,Pojo类中包含pojo。
需求:根据用户名查询用户信息,查询条件放到QueryVo的user属性中
(1)编写QueryVO
package cn.offcn.entity;
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
(2)编写持久层接口UserMapper
public interface UserMapper {
public List<User> getUserByLikeName(QueryVo queryVo);
}
(3)配置接口方法对应的sql文件
<select id="getUserByLikeName" parameterType="cn.offcn.entity.QueryVo"
resultType="cn.offcn.entity.User">
select * from user where name like #{user.name}
</select>
(4)测试QueryVO对象作为参数
@Test
public void testGetUserByLikeName() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//创建User对象
User user = new User();
user.setName("%李%");
QueryVo queryVo = new QueryVo();
queryVo.setUser(user);
//调用deleteUser方法进行模糊查询
List<User> userList = userMapper.getUserByLikeName(queryVo);
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}
3、map集合数据作为参数的处理方式
(1)添加接口方法参数使用map集合
public List<User> getUserByGenderAndAge(Map<String,Object> map);
(2)配置接口对应的sql配置
<!--#{}中参数必须和Map集合中的key保存一致,表示取Map集合中指定key的值。-->
<select id="getUserByGenderAndAge" parameterType="java.util.Map"
resultType="cn.offcn.entity.User">
select * from user where gender=#{sex} and age=#{age}
</select>
(3)测试map集合作为参数
@Test
public void testGetUserByGenderAndAge() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String,Object>();
map.put("sex","男");
map.put("age",22);
List<User> userList = userMapper.getUserByGenderAndAge(map);
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}
4、@Param方式解决多参数处理
(1)@Param注解的介绍
@Param注解用于给方法内的参数取别名,当方法中拥有多个参数时,我们无法一次性将这些参数进行传递,尤其多个参数具有不同的数据类型时无法传递,所以我们利用@Param给每个方法中的参数无一个别名,在映射文件中使用别名进行取值。
(2)添加接口方法参数使用map集合
public List<User> getUserByGenderAndBirthday(@Param("gen") String
gender,Param("birth") Date birthday);
(3)配置接口对应的sql配置
<select id="getUserByGenderAndBirthday" resultType="cn.offcn.entity.User">
select * from user where gender=#{gen} and age=#{birth}
</select>
(4)测试注解方法
@Test
public void testGetUserByGenderAndBithday() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,1997);
calendar.set(Calendar.DAY_OF_MONTH,10);
calendar.set(Calendar.DAY_OF_MONTH,12);
Date birthday = calendar.getTime();
List<User> userList = userMapper.getUserByGenderAndBirthday("女",birthday);
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}
七、Mybatis查询结果封装
1、resultType结果类型
(1)resultType属性介绍
resultType属性可以指定结果集的类型,它支持基本类型和实体类类型。和parameterType一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。
(2)resultType属性的使用
基本类型
编写dao接口方法getTotalRecords参数是基本类型:
/**
* 统计所有记录数
* @return
*/
public int getTotalRecords();
配置接口方法对应的sql语句:
<select id="getTotalRecords" resultType="int">
select count(*) from user
</select>
测试查询结果:
@Test
public void testGetTotalRecords() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//调用getTotalRecords统计记录数
int totalRecords= userMapper.getTotalRecords();
//打印totalRecords
System.out.println("总记录数:"+totalRecords);
//关闭连接
MyBatisUtils.close(session);
}
实体类型
编写dao接口方法getAllInfo:
public List<User> getUsers();
配置接口方法对应的sql语句:
<select id="getUsers" resultType="cn.offcn.entity.User">
select * from user
</select>
测试查询结果:
@Test
public void testGetUser() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//调用getUsers查询所有记录
List<User> userList = userMapper.getUsers();
//遍历结果
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}
(3)特殊情况
如果修改了实体类User中的id属性值,比如修改成了userId,此时查询出的结果没有把表中的id值映射到userId属性中,因为属性和表中的列名不一致,内部无法用反射技术进行映射,所以为空。
public class User implements Serializable {
private Integer userId;
private String userName;
private String gender;
private Integer age;
private Date userBirthday;
public User() {}
public User(String userName, String gender, Integer age, Date userBirthday)
{
this.userName = userName;
this.gender = gender;
this.age = age;
this.birthday = userBirthday;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
//生成其它属性的getter和setter方法
}
@Test
public void testGetUser() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//调用getUsers查询所有记录
List<User> userList = userMapper.getUsers();
//遍历结果
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}
经过上述测试结果发现userId属性为null,没有被赋值。
解决方案:修改映射配置,采用别名设置,让结果集中的列与实体类中的属性对应。
<select id="getUsers" resultType="cn.offcn.entity.User">
select id userId,name userName,gender gender,age age,birthday userBirthdayfrom user
</select>
2、resultMap自定义结果类型
(1)resultMap标签介绍
resultMap标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。在select标签中使用resultMap属性指定引用即可。同时resultMap可以实现将查询结果映射为复杂类型的pojo。
(2)定义接口方法getUserById
/**
* 根据id查询指定User对象
* @param id
* @return
*/
public User getUserById(int id);
(3)在sql的配置文件中定义resultMap
<select id="getUserById" parameterType="int" resultMap="UserResultMap">
select * from user where userId=#{id}
</select>
<resultMap id="UserResultMap" type="cn.offcn.entity.User">
</resultMap>
此处我们使用resultMap而不是resultType,resultType是直接写结果类型,resultMap是映射结果集与类中属性对应关系。
resultMap标签中的id表示一个唯一标记是resultMap的名称。Type表示该resultMap返回的类型。
(4)使用定义的resultMap配置查询的sql语句
<resultMap id="UserResultMap" type="cn.offcn.entity.User">
<id column="id" property="userId"></id>
<result column="name" property="userName"></result>
<result column="gender" property="gender"></result>
<result column="age" property="age"></result>
<result column="birthday" property="userBirthday"></result>
</resultMap>
(5)测试查询结果
@Test
public void testGetUserById() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询user
User user = userMapper.getUserById(1);
//打印user
System.out.println(user);
//关闭连接
MyBatisUtils.close(session);
}
八、配置文件内容解析
在主配置MybatisConfig.xml中,定义了很多标签,我们现在只使用了一部分标签,主配置文件中可以出现的标签用dtd文件进行约束。
1、标签的配置规范,查看dtd规范文件
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT configuration (properties?, settings?, typeAliases?,
typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?,
plugins?, environments?, databaseIdProvider?, mappers?)>
<!ELEMENT databaseIdProvider (property*)>
<!ATTLIST databaseIdProvider
type CDATA #REQUIRED
>
<!ELEMENT properties (property*)>
<!ATTLIST properties
resource CDATA #IMPLIED
url CDATA #IMPLIED
>
<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED
>
<!ELEMENT settings (setting+)>
<!ELEMENT setting EMPTY>
<!ATTLIST setting
name CDATA #REQUIRED
value CDATA #REQUIRED
>
<!ELEMENT typeAliases (typeAlias*,package*)>
<!ELEMENT typeAlias EMPTY>
<!ATTLIST typeAlias
type CDATA #REQUIRED
alias CDATA #IMPLIED
>
<!ELEMENT typeHandlers (typeHandler*,package*)>
<!ELEMENT typeHandler EMPTY>
<!ATTLIST typeHandler
javaType CDATA #IMPLIED
jdbcType CDATA #IMPLIED
handler CDATA #REQUIRED
>
<!ELEMENT objectFactory (property*)>
<!ATTLIST objectFactory
type CDATA #REQUIRED
>
<!ELEMENT objectWrapperFactory EMPTY>
<!ATTLIST objectWrapperFactory
type CDATA #REQUIRED
>
<!ELEMENT reflectorFactory EMPTY>
<!ATTLIST reflectorFactory
type CDATA #REQUIRED
>
<!ELEMENT plugins (plugin+)>
<!ELEMENT plugin (property*)>
<!ATTLIST plugin
interceptor CDATA #REQUIRED
>
<!ELEMENT environments (environment+)>
<!ATTLIST environments
default CDATA #REQUIRED
>
<!ELEMENT environment (transactionManager,dataSource)>
<!ATTLIST environment
id CDATA #REQUIRED
>
<!ELEMENT transactionManager (property*)>
<!ATTLIST transactionManager
type CDATA #REQUIRED
>
<!ELEMENT dataSource (property*)>
<!ATTLIST dataSource
type CDATA #REQUIRED
>
<!ELEMENT mappers (mapper*,package*)>
<!ELEMENT mapper EMPTY>
<!ATTLIST mapper
resource CDATA #IMPLIED
url CDATA #IMPLIED
class CDATA #IMPLIED
>
<!ELEMENT package EMPTY>
<!ATTLIST package
name CDATA #REQUIRED
>
2、properties标签详解
在使用properties标签配置时,在xml中可以引用properties属性文件中key的值,日后修改properties属性文件中key的值时,不用修改xml文件,从而提高了效率。
(1)新建一个dbconfig.properties属性文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis001
jdbc.username=root
jdbc.password=root
(2)在MybatisConfig.xml中可以引用属性文件中key的值
<properties resource="dbconfig.properties"></properties>
<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>
3、typeAliases标签详解
(1)在MybatisConfig.xml中定义别名
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.offcn.entity.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="cn.offcn.entity"/>
<package name=" 其它包 "/>
</typeAliases>
(2)在userMapper.xml中使用别名
<select id="getUsers" resultType="user">
select * from user
</select>
<select id="getUserById" parameterType="int" resultMap="UserResultMap">
select * from user where userId=#{id}
</select>
<resultMap id="UserResultMap" type="user">
<id column="id" property="userId"></id>
<result column="name" property="userName"></result>
<result column="gender" property="gender"></result>
<result column="age" property="age"></result>
<result column="birthday" property="userBirthday"></result>
</resultMap>
4、mappers映射器标签详解
mappers映射器用于指定映射文件的位置
<!--使用相对于类路径的资源-->
<mappers>
<mapper resource="cn/offcn/dao/UserDao.xml"/>
</mappers>
<!--使用mapper接口类路径-->
<mapper class="cn.offcn.dao.UserDao"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
九、Mybatis自动返回主键值
1、返回主键值技术的业务应用场景
对于自增主键在某些业务中保存一个对象后,需要使用到这个主键完成后续的业务逻辑。
2、接口中编写addUser方法
/**
* 保存user对象
* @param user
*/
public void saveUser(User user);
3、在sql的配置文件中添加接口方法对应的sql的配置
<select id="saveUser" parameterType="cn.offcn.entity.User">
insert into user (name,gender,age,birthday) values(#{name},#{gender},#
{age},#{birthday})
</select>
4、在sql标签上添加返回自增长的主键值的配置
第一种方式:
<insert id="saveUser" parameterType="cn.offcn.entity.User"
useGeneratedKeys="true" keyProperty="id">
insert into user (name,gender,age,birthday) values(#{name},#{gender},#
{age},#{birthday})
</insert>
useGeneratedKeys: 表示开启获取自增主键值。
keyProperty: 表示从表中取到主键值后赋给User类中的哪个属性。
第二种方式:使用selectKey标签和mysql内置函数
<insert id="saveUser" parameterType="cn.offcn.entity.User">
<selectKey keyColumn="id" keyProperty="id" resultType="int"
order="AFTER">
select last_insert_id()
</selectKey>
insert into user (name,gender,age,birthday) values(#{name},#{gender},#
{age},#{birthday})
</insert>
keyColumn:指定取数据库中哪一列的值(通常指主键列)。
keyProperty: 表示取出主键值后赋值User对象的哪个属性。
resultType: 表示对象的属性类型
order:表示完后sql语句之前还是之后把主键值赋给实体类对应属性。
5、测试
@Test
public void testsaveUser() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//创建User对象
User user=new User("刘备","男",30,new Date());
//保存User对象
userMapper.saveUser(user);
//打印user的id属性值
System.out.println(user.getId());
//提交事务
session.commit();
//关闭连接
MyBatisUtils.close(session);
}
十、sql片段
1、sql的配置文件中出现sql冗余
在开发中,SQL的拼接很常见,有很多对拼接的sql具有重复性高的特点,有sql冗余,不仅不美观还导致映射文件配置臃肿,这时最好把重复的SQL片段,尤其在动态sql中应用中更加显著。
2、定义sql片段
<!--使用sql标签定义一个sql片段-->
<sql id="baseColumn ">
id,name,gender,age
</sql>
3、使用sql片段
<select id="getUsers" resultType="cn.offcn.entity.User">
select <include refid= "baseColumn"></include> from user
</select>