一、MyBatis的基本组成
MyBatis的核心组件:
1.1 构建SqlSessionFactory
每个MyBatis的应用都是以SqlSessionFactory的实例为中心的。SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactory是一个工厂接口,它的任务是创建SqlSession。SqlSession类似于一个JDBC的Connection对象。MyBatis提供了两种模式去创建SqlSessionFactory:一种是XML配置的方法,一种是编码方式,推荐使用XML配置的方式。
所以就需要一个主配置文件sqlMapConfig.xml,用来进行数据库的相关配置。SqlSessionFactoryBuilder就根据sqlMapConfig.xml,通过SqlSessionFactoryBuilder的build方法来创建来创建SqlSessionFactory。
可以看出,build方法分为两类,一类是使用字符流,读取sqlMapConfig.xml,另一类是使用字节来读取。
查看源码会发现,最终都会调用:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
其中config就是通过流读取的配置文件所对应的对象,DefaultSqlSessionFactory是SqlSessionFactory的实现类
下面以XML方式为例,构建一个SqlSessionFactory
先来创建sqlMapConfig.xml:
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<typeAlias type="com.xiaowen.pojo.User" alias="User"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/xiaowen/pojo/User.xml"/>
mappers>
configuration>
对上面的配置做一下说明:
(1)、这里配置了一个别名User,它代表com.xiaowen.pojo.User,这样我们就可以在MyBatis上下文中引用它了。
(2)、配置了环境内容,默认使用id时development的环境配置,包含以下两方面内容:
(3)、配置映射器
最后引入了User.xml,在User.xml配置了对User表的增删改查操作,以及从数据库返回的数据映射到哪个POJO上。
创建SqlSessionFactory的java代码:
//加载核心配置文件
String resource="sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
这里我们创建了一个XML文件输入流,用SqlSessionFactoryBuilder读取XML的信息来创建SqlSessionFactory的对象。
MyBatis的解析程序会将sqlMapConfig.xml文件配置的信息解析到Configuration类对象里面,然后利用SqlSessionFactoryBuilder读取这个对象为我们创建sqlSessionFactorty。
1.2 构建SqlSession
SqlSession接口类似于一个JDBC的Connection接口对象,SqlSession对象由SqlSessionFactory的openSession方法创建,我们需要保证每次用完正常关闭它,所以正确的做法是把关闭的SqlSession接口代码写finally语句中保证每次都会关闭SqlSession,让连接资源归还给数据库。
SqlSession的用途主要有两种
(1) 获取映射器,让映射器通过命名空间和方法名找到对应的SQL,发送给数据库执行后返回结果。
(2)直接通过命名信息去执行SQL返回结果,在SqlSession层可以通过update、insert、select、delete等方法,带上SQL的id来操作XML中配置好的SQL,从而完成我们的工作;与此同时也支持事务,通过commit,rollback方法提交或者回滚事务。
1.3 配置映射器
映射器由Java接口和XML文件(或注解)共同组成的,它的作用如下。
映射器的实现方式有两种,一种是通过XML文件方式实现,一种是通过代码方式实现。推荐使用XML方式,
XML文件配置方式实现Mapper
使用XML文件配置是MyBatis实现Mapper的首选方式。它由一个Java接口和一个XML文件构成。
第一步:给出Java接口:
package com.xiaowen.mapper;
import com.xiaowen.pojo.User;
public interface UserMapper {
public User findUserById(Integer id);
}
这里定义了一个接口,它有一个方法findUserById,通过ID找到用户
第二步:给出一个映射XML文件:
<mapper namespace="com.xiaowen.mapper.UserMapper">
<select id="findUserById" parameterType="Integer" resultType="User">
select * from user where id = #{id}
select>
mapper>
描述一下上面的XML文件做了什么:
package com.xiaowen.pojo;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public Integer getId() {
return id;
}
public void setId(Integer 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 + "]";
}
}
@Test
public void fun1() throws Exception{
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = ac.getBean(UserMapper.class);
User user = userMapper.findUserById(10);
System.out.println(user);
}
1.4 生命周期
SqlSessionFactoryBuilder
SqlSessionFactoryBuilder是利用XML或者Java编码获得资源来构建SqlSessionFactory的。通过它可以构建多个SessionFactory。所以它的生命周期只存在于方法的局部,它的作用就是生产SqlSessionFactory对象。
SqlSessionFactory
SqlSessionFactory的作用是创建SqlSession,而SqlSession就是一个会话,相当于JDBC的Connection对象。每次应用程序需要访问数据库,就要通过SqlSessionFactory创建SqlSession,所以SqlSession应该在MyBatis应用的整个生命周期中。而如果我们多次创建同一个数据库的SqlSessionFactory,会打开更多的连接资源,因此SqlSessionFactory的责任是唯一的,它的责任就是创建SqlSession,所以应该采用单例模式,一个数据库值对应一个SqlSessionFactory,管理好数据库资源的分配,避免过多的Connection被消耗。
SqlSession
SqlSession是一个会话,相当于JDBC的connection对象,它的生命周期应该是在请求数据库处理事务的过程中。它是一个线程不安全的对象,在涉及多线程的时候,要注意其隔离级别。此外,每次创建的SqlSession都必须及时关闭它。
Mapper
Mapper是一个接口,而且没有任何实现类,它的作用是发送SQL,然后返回我们需要的结果,或者执行SQL从而修改数据库的数据,因此它应该在一个SqlSession事务方法之内,是一个方法级别的东西。它就如同JDBC中的一条SQL语句的执行,它最大的范围和SqlSession是相同的。
二、实例
POJO:与数据库中的表对应:
User
package com.xiaowen.pojo;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public Integer getId() {
return id;
}
public void setId(Integer 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 + "]";
}
}
UserMapper接口:
package com.xiaowen.mapper;
import com.xiaowen.pojo.User;
public interface UserMapper {
//遵循四个原则:
//接口方法名== UserMapper.xml中的id名
//返回值类型与UserMapper.xml文件中返回值类型要一致
//方法的入参类型与UserMapper.xml中入参的类型要一致
//命名空间与接口绑定
public User findUserById(Integer id);
public void insertUser(User user);
public void updateUserById(User user);
public void deleteUserById(Integer id);
}
UserMapper.xml与UserMapper接口进行映射:
<mapper namespace="com.xiaowen.mapper.UserMapper">
<select id="findUserById" parameterType="Integer" resultType="User">
select * from user where id = #{v}
select>
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" resultType="Integer" order="AFTER">
select LAST_INSERT_ID()
selectKey>
insert into user (username,birthday,address,sex) values (#{username},#{birthday},#{address},#{sex})
insert>
<update id="updateUserById" parameterType="User">
update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}
update>
<delete id="deleteUserById" parameterType="Integer">
delete from user where id = #{id}
delete>
mapper>
主配置文件:
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<typeAlias type="com.xiaowen.pojo.User" alias="User"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
dataSource>
environment>
environments>
<mappers>
<mapper class="com.xiaowen.mapper.UserMapper"/>
mappers>
configuration>
测试方法:
@Test
public void findUserById() throws Exception {
//加载核心配置文件
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获得Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(10);
System.out.println(user);
sqlSession.close();
}
@Test
public void insertUser() throws Exception {
//加载核心配置文件
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获得Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("小文");
user.setSex("1");
user.setAddress("南京");
userMapper.insertUser(user);
//如果不提交,事务会自动回滚,无法插入数据到数据库
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUserById() throws Exception {
//加载核心配置文件
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获得Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("小文");
user.setSex("1");
user.setAddress("北京");
user.setId(31);
userMapper.updateUserById(user);
//如果不提交,事务会自动回滚,无法插入数据到数据库
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteUserById() throws Exception {
//加载核心配置文件
String resource = "sqlMapConfig.xml";
InputStream in = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获得Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.deleteUserById(31);
//如果不提交,事务会自动回滚,无法插入数据到数据库
sqlSession.commit();
//释放资源
sqlSession.close();
}