文章目录
一.认识MyBatis
MyBatis就是一个ORM框架(操作数据库)
- MyBatis与Hibernate的区别
MyBatis自己写SQL,性能更好控制
- MyBatis与JDBC的区别
MyBatis只需要关注SQL,其它完成了封装
- MyBatis的三大核心对象
SqlSessionFactoryBuilder
主要是用来创建SqlSessionFactory的
SqlSessionFactory
整个应用对象中只有1个对象 生命周期:随着tomcat启动而创建,tomcat关闭而销毁
SqlSession
每个线程都应该拿到一个SqlSession,多个线程不能共享
二.Mybatis的基本配置
- 导包(核心,依赖包,数据库驱动包)
- 有表,有domain
- 核心配置文件 mybatis-config.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>
<!--引入 jdbc.properties文件-->
<properties resource="jdbc.properties" />
<!--配置连接数据库环境-->
<environments default="mysql">
<!--给环境取个别名-->
<environment id="mysql">
<!--配置事物类型-->
<transactionManager type="JDBC"/>
<!--配置连接池对象(数据源)-->
<dataSource type="POOLED">
<!--连接数据库的四大金刚-->
<property name="driver" value="${driver}" />
<!--createDatabaseIfNotExist=true 没有就自动创建数据库-->
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 读取SQL的映射文件 -->
<mapper resource="com/gxr/mybatis/_01hello/dao/impl/ProductDaoImpl.xml"/>
</mappers>
</configuration>
- 创建映射文件 ProductMapper.xml
<?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:命名空间(一个domain对应一个这个xml)
-->
<mapper namespace="com.gxr.domain.ProductMapper">
<!--
如果到时候想找到这条SQL: namespace+id
等会要找到它:com.gxr.domain.ProductMapper.findOne
parameterType:代表传参类型
long -> Long _long -> long
resultType:返回的某一个条数的类型(必需写全限定名)
-->
<select id="findOne" parameterType="long" resultType="com.gxr.domain.Product" >
select * from product where id = #{id}
</select>
</mapper>
- 完成功能
//SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession
@Override
public Product findOne(Long id) {
try {
//1.读取核心配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//2.创建一个对象:SqlSessionFactory 相当于咱们JPA:EntityManagerFactory
// SqlSessionFactoryBuilder:构造者模式
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//3.创建一个对象:SqlSession 相当于当前JPA:EntityManager
SqlSession session = factory.openSession();
//4.session操作数据库(读取数据)
/**
* 方式中有两个值:
* 第一个值(statement):找SQL的字符串
*/
Product product = session.selectOne("com.gxr.domain.ProductMapper.findOne",id);
return product;
} catch (Exception e) { //注意,不要用IO异常(很多错看不出来)
e.printStackTrace();
}
return null;
}
三.MyBatisCRUD
3.1 MyBatisUtil
public class MybatisUtil {
private MybatisUtil(){}
private static SqlSessionFactory sqlSessionFactory;
//在静态代码块中创建SqlSessionFactory对象
static {
try {
/*InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");*/
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (Exception e) {
e.printStackTrace();
System.out.println("解析xml失败");
}
}
//返回SqlSession对象
public static SqlSession openSession() throws Exception {
if(sqlSessionFactory == null){
throw new Exception("解析xml异常。。。");
}
return sqlSessionFactory.openSession();
}
}
3.2 CRUD的关键代码
session.insert("com.gxr.domain.ProductMapper.save", product);
session.update("com.gxr.domain.ProductMapper.update", product);
session.delete("com.gxr.domain.ProductMapper.delete",id);
Product product = session.selectOne("com.gxr.domain.ProductMapper.findOne",id);
List<Product> products = session.selectList("com.gxr.domain.ProductMapper.findAll");
- 增删改需要提交事务
四.注意点与细节
4.1 添加时需要id
- useGeneratedKeys:是否要返回id
- keyColumn:数据库中的主键对应的列
- keyProperty:domain中对应的主键属性
- id返回到传过来的对象中
<insert id="save" parameterType="product"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
...
4.2 别名
- 内置别名(文档中有)
- 自定义别名 mybatis-config.xml\
- 别名不区别大小写
- 注意它的配置顺序(如果配置错误会有提示)
<!-- 配置别名 -->
<typeAliases>
<!-- 配置一个别名(不区分大小写) -->
<!--<typeAlias type="com.gxr.domain.Product" alias="product" />-->
<package name="com.gxr.domain" />
</typeAliases>
4.3 日志管理
在资源根目录创建:log4j.properties
# log4j.properties(日志文件:)
# 全局 配置根
# ERROR错误的日志 WARN:警告 INFO:普通信息 DEBUG:调试日志 TRACE:日志
# log4j常见的日志等级: trace<debug<info<warn<error
log4j.rootLogger=ERROR,console
# 输出局部的日志信息 打印的日志等级要大于或者等于trace等级 (包名改成你自己的包名)
log4j.logger.com.gxr=TRACE
# 打印的日志规则 (日志打印到控制台中)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
# 日志打印的一种格式(可以灵活地指定布局模式)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 日志打印的格式是什么样子的 %d:日期 %p:优先级 %c:类的全名 %m:输出的结果 %n:换行(布局规则)
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
4.4 列名与属性名不一致
- 添加与修改在相应位置修改名称即可
- 查询需要创建一个resultMap
- 使用的时候返回结果必需是resultMap
<!--
准备一个映射(ORM)配置
resultMap:结果映射
-->
<resultMap id="productMapper" type="product">
<!--如果是主键不一致,使用id这个标签-->
<id column="id" property="id" />
<!--
result:某一个属性的映射
column:列名(表中) property:属性名(对象中)
-->
<result column="dir_id" property="dirId" />
</resultMap>
<!-- 查询所有数据 -->
<select id="findAll" resultMap="productMapper" >
select * from product
</select>
五.映射Mapper
- 接口方法映射到对应的SQL
- Mapper.xml的命名空间名称就是Maper接口的全限定名
- Mapper接口上也可以写SQL(不建议这么做)
5.1 employeeMapper.xml
<!--这个命名空间的名称就是咱们Mapper接口的全限定名-->
<mapper namespace="com.gxr._02_mapper.mapper.EmployeeMapper">
<!--这个id的名称必需和映射的EmployeeMapper的方法名一致-->
<insert id="save" parameterType="employee">
...
</insert>
<select id="findAll" resultType="employee">
...
</select>
</mapper>
5.2 EmployeeMapper
package com.gxr._02_mapper.mapper;
public interface EmployeeMapper {
void save(Employee employee);
// @Select("select * from employee")
List<Employee> findAll();
}
5.3 调用 Mapper的方法
SqlSession session = MyBatisUtil.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
mapper.findAll().forEach(e -> System.out.println(e));
六.高级查询
- 准备一个Query对象(封装所有条件)
- 模糊查询
concat("%",#{name},"%")
- 抽取公共的sql语句
- 遇到特殊符号 1.转义
<
2.CDATA段<![CDATA[...]]>
- 使用where标签(第一个and变成where)
- if中有多个条件使用 and/or 进行关联
- 如果出现相同的代码,可以单独抽取
sql标签
,引用include
即可
6.1 动态高级查询
<select id="findByQuery" parameterType="employeeQuery" resultType="employee">
select * from employee <include refid="whereSql" />
</select>
<!--准备代码片断-->
<sql id="whereSql">
<where>
<if test="name!=null and name!=''">
and name like concat("%",#{name},"%")
</if>
<if test="minAge!=null">
and age >= #{minAge}
</if>
<if test="maxAge!=null">
<![CDATA[ and age<=#{maxAge} ]]>
</if>
</where>
</sql>
七. 批量删除,添加
7.1 批量删除
首先知道sql
delete from 表名 where id in (?,?,..)
collection="":代表你要循环的是什么? array/list
如果传过来的是数据,写array(集合就写list)
item:循环的每一个数据
open:拼接字符串以什么开始
close:拼接字符串以什么结尾
separator:拼接的时候每个值使用,隔开
index:遍历的下标
7.1.1 传数组的方法
<delete id="batchDelete" parameterType="long[]">
delete from employee where id in
<foreach collection="array" item="v" open="(" close=")" separator=",">
#{v}
</foreach>
</delete>
7.1.2 传集合的方式
<delete id="batchDelete" parameterType="list">
delete from employee where id in
<foreach collection="list" item="v" open="(" close=")" separator=",">
#{v}
</foreach>
</delete>
7.2 批量添加
首先知道sql
insert into 表名 (p1,p2,...) values (#{p1},#{p2}),(#{p1},#{p2}),...
<insert id="batchSave" parameterType="list">
insert into employee (name,age,sex) values
<foreach collection="list" item="emp" separator=",">
(#{emp.name},#{emp.age},#{emp.sex})
</foreach>
</insert>