mybatis中,封装了一个sqlsession 对象(里面封装有connection对象),由此对象来对数据库进行CRUD操作。
运行流程
mybatis有一个配置的xml,用于配置数据源、映射Mapping,xml的文件名可以任取,为了方便,我们还是起mybatis-config.xml
我们读取此配置的xml,获得一个sqlsession,之后由此对象类进行数据库的CRUD操作
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = factory.openSession();
入门使用
1. 创建实体类和Dao类
2. 配置mybatis-config.xml文件,配置数据源
3. 定义连接数据库工具,可以获得sqlsession对象
Dao类中每次进行CRUD操作,都要执行一次openSession方法
来获得SqlSession对象
,造成资源的浪费和代码的重复
所以,和之前的JdbcUtil
工具类一样,我们也定义定义一个工具类MyBatisUtil
,用来返回SQLSession对象
static SqlSessionFactory sqlSessionFactory = null;
static {
try {
// 加载mybatis配置文件,并创建SqlSessionFactory实例
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//这个build方法可以接受几种不同的参数,如Reader/InputSteam等
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
public static void closeSqlSession(SqlSession sqlSession){
if (sqlSession != null) {
sqlSession.close();
}
}
4. sql语句写在mapper中
mapper文件放在了resources下面
Mybatis中,sql语句则是写在了xml文件中,这些xml文件也称为mapper映射文件
mapper标签如果带有xmln属性,IDEA会报解析xml错误,得把xmln属性删除
5. 在mybatis-config.xml文件中注册mapper
6. dao类通过sqlsession进行查询
SqlSession sqlSession = MybatisUtil.getSqlSession();
// 调用语句,如果有参数,传入参数
//参数为命名空间namespace+id,执行xml中的sql语句
List list = sqlSession.selectList("employeeMapper.selectAll");
PS:如果是插入、更新和删除操作,还需要提交操作,默认是不会自动提交的
sqlSession.commit();
补充
1.typeAliases标签
resultType
属性需要全类名,我们可以使用typeAliases
标签来简化输入
typeAliases
标签需要在mybatis-config.xml
文件中进行设置
之后我们的mapper文件中就可以这样写
我这里只介绍用法,详解请看下面的参考链接
参考 MyBatis 配置 typeAliases 详解
2.引入mapper的四种方法
1. 文件路径注册
2. 包名扫描注册
使用这种,必须保证xxxMapper.java和xxxMapper.xml两者名字一模一样!而且是要在同一包里
3. 类名注册
4. url注册
参考:配置MyBatis时报错信息的解决方案
SQLSession方法说明
方法名 | 说明 |
---|---|
insert | 插入 |
delete | 删除 |
update | 更新 |
selectOne | 查找单行结果,返回一个Object |
selectList | 查找多行结果,返回一个List |
使用和之前一样,第一个参数传入一个namespce+id,就可以找到指定的mapper文件里面的sql语句,并执行
CRUD
查询
Employee中,属性名和表的列名对应
如果属性和表的列名不一致,可以使用列名映射resultMap标签,(也就是自动转为别名)
带条件查询
//使用
Employee e = sqlsession.selectOne("employeeMapper.selectById",7369);
上面的select语句相当于一个预编译语句
String s = "SELECT * FROM employee WHERE empno=?";
PreparedStatement ps = conn.prepareStatement(s);
ps.setInt(1,empno);
多条件查询
可以使用where标签,当然,之前的单条件也可以使用where标签,where标签好处是会自动删除多余的and
大小比较条件
条件中有大小比较,<
号得通过CDATA存放条件
#与$区别:
${}
用在我们能够确定值的地方,也就是我们程序员自己赋值的地方。
而#{}
一般用在用户输入值的地方!!
参考:
MyBatis中#{}和\({}的不同和\){}的妙用
模糊查询:
模糊查询中需要使用%
等通配符,我们可以在xml中定义好,自动拼接通配符
动态查询
Mybatis中提供了if
标签用来实现动态查询,和JSTL标签库使用类似
插入
主键为序列
某个主键是由oracle中的序列生成的
select EMP_SEQ.nextval from dual
insert into EMPLOYEE
values (#{empno},#{ename},#{job},#{mgr,jdbcType=INTEGER},#{hiredate,jdbcType=DATE},#{sal,jdbcType=DOUBLE},#{comm,jdbcType=DOUBLE},#{deptno,jdbcType=INTEGER})
复用sql语句
把insert要插入的列名和数值写在sql标签里,之后方便重用,之后重用的时候需要使用include
子标签拼接sql语句
empno,
ENAME,
JOB,
MGR,
HIREDATE,
SAL,
COMM,
DEPTNO,
#{empno},
#{ename},
#{job},
#{mgr},
#{hiredate},
#{sal},
#{comm},
#{deptno},
select EMP_SEQ.nextval from dual
insert into EMPLOYEE
更新
update EMPLOYEE
ENAME=#{ename},
JOB=#{job},
MGR=#{mgr},
HIREDATE=#{hiredate},
SAL=#{sal},
COMM=#{comm},
DEPTNO=#{deptno},
where EMPNO=#{empno}
update EMPLOYEE
ENAME=#{ename},
JOB=#{job},
MGR=#{mgr},
HIREDATE=#{hiredate},
SAL=#{sal},
COMM=#{comm},
DEPTNO=#{deptno},
where EMPNO=#{empno}
删除
delete EMPLOYEE EMPNO=#{empno}
w3c select标签、delete标签等详解
高级使用
1.动态代理
我们之前,上面都是在Dao类中写上一段sqlsession.selectOne/selectList,还是比较麻烦
所以mybatis提供了一种简单的方法,使用动态代理(接口类)可以简化步骤
Mybatis中有这样的约定:
- 接口方法名与mapper中的id相同
- 接口方法参数与parameterType类型相同
- 接口方法的返回值类型与resultType类型相同
满足上面的条件,Mybatis就会将接口类中的方法和mapper中的sql语句一一对应起来,而不需要再次新建一个Dao,在Dao类里面编写方法
具体步骤:
1. 实体类编写
2. 新建接口类
如果方法的返回值为void,则mapper中就不需要定义resultType属性
如果方法返回值是List,mapper中的resultType为泛型T
package com.wan.mapping;
import com.wan.bean.Employee;
import java.util.List;
/**
* @author StarsOne
* @date Create in 2019/9/16 0016 20:38
* @description
*/
public interface EmployeeMapper {
List selectAll();
}
2. 编写mapper.xml
3. 注册mapper
这里我们由于使用了package注册mapper,一定保证xxmapper.java和xxmapper.xml两个名字相同,大小写都要一样
保证Mapper.xml和接口的那个Mapper在相同的包路径,在mybatis配置xml文件指定
...
4. 使用
使用还是和之前一样,获得SqlSession对象,此对象有个getMapper方法,把接口类传入,就可以回调接口的方法了
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = factory.openSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
List employees = mapper.selectAll();
接口类中的方法名与EmployeeMapper.xml中的对应
使用:
EmployeeMapper mapper = sqlsession.getMapper(EmployeeMapper.class);
mapper.selectById(7369);
2.遍历列表
Mybatis中提供了foreach标签,用于遍历
如果方法参数传入了一个List,可以使用此标签遍历,例子如下:
foreach标签的属性主要有 item,index,collection,open,separator,close,使用和JSTL标签里面的foreach标签差不多
属性名 | 说明 |
---|---|
item | 表示集合中每一个元素进行迭代时的别名 |
index | 指定一个名字,用于表示在迭代过程中,每次迭代到的位置, |
open | 表示该语句以什么开始, |
separator | 表示在每次进行迭代之间以什么符号作为分隔 符, |
close | 表示以什么结束。 |
关键属性:collection
- 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
- 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
- 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key
参考:mybatis 中 foreach collection的三种用法
3.考虑线程安全
使用ThreadLocal对象,保证每个线程取出的SqlSession是同一个对象
方法 | 说明 |
---|---|
void set(Object value) | 设置当前线程的线程局部变量的值。 |
public Object get() | 该方法返回当前线程所对应的线程局部变量。 |
public void remove() | 将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。 |
protected Object initialValue() | 返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。 |
static ThreadLocal threadLocal = new ThreadLocal();
//设置
threadLocal.set(sqlsession);
//取出
SqlSession s = threadLocal.get();
4.嵌套查询
5.分页查询
分页的话,像以前那样使用三层嵌套查询也可以实现。
不过,有开发者为Mybatis开了个一个插件PageHelper,可以用来更为简单地使用分页查询
1.添加jar包
com.github.pagehelper
pagehelper
REALSE
2.配置拦截器插件
3.代码使用
只有在查询之前调用过startPage
或者是offsetPage
方法,后面的查询出来的List结果就会进行分页查询
下面的两个都是查询第一页,每一页有10条数据
//第二种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(1, 10);
List employees = employeeMapper.selectAll();
//第三种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.offsetPage(1, 10);
List employees = employeeMapper.selectAll();
这里提一下,这个插件还带有一个PageInfo
类,里面有可以记录各种信息
刚开始,我以为是和我之前自己封装的Page一样,详情请看Jsp学习笔记(4)——分页查询
但是,其实不一样的,这个PageInfo就是一个封装而已,只是用来存放数据而已,里面有各种信息
属性 | 说明 |
---|---|
pageNum | 当前页号(第几页) |
pageSize | 每页的显示的数据个数 |
size | 当前页的显示的数据个数 |
startRow | 当前页面第一个元素在数据库中的行号 |
endRow | 当前页面最后一个元素在数据库中的行号 |
pages | 总页数 |
prePage | 上一页的页号 |
nextPage | 下一页页号 |
isFirstPage | 是否为第一页 |
isLastPage | 是否为最后一页 |
hasPreviousPage | 是否有前一页 |
hasNextPage | 是否有下一页 |
navigatePages | 导航页码数 |
navigatepageNums | 所有导航页号 |
navigatePages | 导航条上的第一页 |
navigateFirstPage | 导航条上的第一页 |
navigateLastPage | 导航条上的最后一页 |
有个getTotal
方法,可以获得查询结果的总记录数
PageHelper.startPage(1, 10);
List employees = mapper.selectAll();
PageInfo pageInfo = new PageInfo<>(employees);