一、Mybatis简介
1、Mybatis执行步骤
- 读取配置文件
mybatis-config.xml
,主要是获取数据库连接和运行环境信息 - 加载映射文件mapper.xml,也就是sql映射文件,需要在mybatis-config.xml中加载才能被执行。
- 创建SqlSessionFactory
- 根据SqlSessionFactory创建SqlSession
- 使用SqlSession对象操作数据库,包括增删改查和事务提交
- 关闭SqlSession
二、Mybatis与Maven整合
1、Maven 依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
2、mybatis配置文件
src/man/resources/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>
<!--数据库环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/淄矿大数据平台?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--每一个Mapper都需要在此注册,一下三种方式都可以-->
<mappers>
<mapper resource="Mapper.xml/SjddSjsctzMapper.xml"/>
<!--一下两种方式要注意,存xml和存接口的文件夹名字要相同-->
<mapper class="ore.example.mapper.SjddSjsctzMapper"/>
<mapper package name="ore.example.mapper"/>
</mappers>
</configuration>
3、工具类
package org.example.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;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
// 获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取SqlSession实例,SqlSession包含了面向数据库执行SQL命令所需的所有方法
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
}
4、Mapper接口
package org.example.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.model.SjddSjsctz;
import java.util.List;
@Mapper
public interface SjddSjsctzMapper {
List<SjddSjsctz> selectAll();
}
5、Mapper.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绑定对应的Mapper接口-->
<mapper namespace="org.example.mapper.SjddSjsctzMapper">
<select id="selectAll" resultType="org.example.model.SjddSjsctz">
select * from sjdd_sjsctz;
</select>
</mapper>
6、mapper读取数据
@Test
public void testMybatis() {
// 第一步:获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 第二部:getMapper
SjddSjsctzMapper sjddSjsctzMapper = sqlSession.getMapper(SjddSjsctzMapper.class);
for (SjddSjsctz sjddSjsctz : sjddSjsctzMapper.selectAll()) {
System.out.println(sjddSjsctz);
}
// 第三步:关闭SslSession
sqlSession.close();
}
三、简单CURD操作
1、增、删、改、查 示例
// 一、查询:可以传bean、map、@param修饰的一个或多个参数、顺序传的单个或多个参数
List<SjddSjsctz> selectAll();
// 二、插入:可以传bean、map、@param修饰的一个或多个参数、顺序传的单个或多个参数
// id自增,可以手动指定一个id传进去,也可以不传
int insertOne(Map<String,Object> map);
2、模糊查询
两种方式
// Java代码里的模糊查询参数,传递通配符%%
List<User> userList = mapper.getUserLike("%李%");
select * from user where username like '#{username}';
List<User> userList = mapper.getUserLike("李");
select * from user where username like concat('%',#{username},'%');
3、批量插入
@Test
public void testInsert() throws Exception {
SqlSession sqlSession = MybatisUtils.sqlSessionFactory.openSession(ExecutorType.BATCH);
SjddSjsctzMapper mapper = sqlSession.getMapper(SjddSjsctzMapper.class);
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUsername(UUID.randomUUID().toString());
user.setPassword(UUID.randomUUID().toString());
mapper.insertMany(user);
}
sqlSession.commit();
}
4、返回自增主键
当使用insert或update语句时,返回语句影响记录的自增主键值。
-
useGenerateKeys="true/false"
这回让MyBatis使用JDBC的getGenerateKeys方法,来取出由数据库内部生成的主键,默认false。如果设置为 true,将强制使用自动生成主键。 -
keyProperty="id"
,指定返回自增主键的值,将自增主键值赋予入参值实体类的id
属性。
User user = new User();
user.setUsername("username");
user.setPassword("password");
user.setRoles("roles");
user.setEnable((byte) 1);
int i = mapper.insertOne(user);
System.out.println(i);
System.out.println(user.getId()); // 得到返回的主键
int insertOne(User user);
-- 将主键返回给传来的user对象的id属性
<insert id="insertOne" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user(username, password,enable, roles)
values (#{username}, #{password}, #{enable}, #{roles});
</insert>
5、SQL执行结束的返回值
- insert、delete、update语句:
用int返回类型,返回执行的SQL语句影响的记录条数,若果是0则表示没有做更改。
- select语句的返回值类型如下:
使用查询语句执行后,数据库返回的实际类型。
- List/map
- javabean
- resultMap
6、mapper.xml接收的参数类型
(1)parameterType
- 接收单个参数,参数类型为基本类型/包装类型时,mapper.xml里的参数名可以随便写都能取到值:#{xx}
- 接收多个参数,参数类型为基本类型/包装类型时,写入对应的参数名;或者按照顺序写#{0}...#{n}
- 接收map、或实体类,mapper.xml里的参数名要和map的key或实体类里的属性名相对应。
int addUser(Map<String, Object>);
<insert id="addUser" parameterType="map">
insert into sjdd_sjsctz (id, name, password) values(#{name},#{password}) ;
</insert>
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "admin");
map.put("password", "123456");
mapper.addUser(map);
(2)parameterMap
用的比较少
7、mapper.xml返回的参数类型
这里的返回参数,一般是select语句用到的返回数据的参数类型。
(1)resultType
- 返回实体类
- 返回map
- 单字段返回基础类型
(2)resultMap
简单用法是解决表字段与实体类属性不一致的问题。
- 方式一:查询语句起别名
<select id="selectAll" resultType="User">
select id, name, pwd as password from user;
</select>
- 方式二:返回值类型设置成:
resultMap
<!--只需要将不一致的字段进行对应,相当于返回了User,但修改了不一致的字段-->
<resultMap id="resultMap" type="User">
<result column="password" property="pwd"/>
</resultMap>
<select id="selectAll" resultMap="resultMap">
select id, name, pwd from user;
</select>
四、复杂查询
1、动态SQL
(1)if
<select id="select" resultType="Blog">
SELECT * FROM BLOG WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
(2)foreach
- 查询
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT * FROM POST P WHERE ID in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
- 批量插入
ArrayList<Object> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUsername(UUID.randomUUID().toString());
user.setPassword(UUID.randomUUID().toString());
users.add(user);
}
int i = mapper.insertMany(users);
System.out.println(i);
int insertMany(List list);
<insert id="insertMany">
insert into user(username, password) values
<foreach collection="list" item="item" separator=",">
(#{item.username}, #{item.password})
</foreach>
</insert>
(3)choose、when、otherwise
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
(4)set
待补充。。。。
2、多表查询
多表查询,xml里返回类型需要用resultMap,自定义返回的字段,对一使用association,对多使用collection。实体类里要加入对一的属性。
- 关联-association【对一】
- 集合-collection 【对多】
javaType 用来指定实体类中属性的类型
ofType 用来指定映射到List或集合中的pojo类型,泛型中的约束类型
(1)一对一
一对一的,使用resultMap和association。可以对javabean添加属性也可以
- 假设一个Article对应一个Author,Article里存放Author的id。在Article的实体类里,增加Author。
@Data
public class Article {
private String articleId;
private String title;
private Integer authorId;
// 加入需要关联的实体类
private Author author;
}
- 编写resultMap
<resultMap id="resultMap" type="Article">
<!-- 一下三条不能省略 -->
<id property="articleId" column="article_id"/>
<result property="title" column="title"/>
<result property="authorId" column="author_id"/>
<!-- 关联的实体类属性 -->
<association property="author">
<id property="id" column="id"/>
<result property="author" column="author"/>
</association>
</resultMap>
- 编写查询语句
<select id="selectOneToOne" resultMap="resultMap">
select a.author_id, a.title, a.article_id, b.id, b.author
from article a, author b where a.author_id = b.id;
</select>
(2)一对多
- 一的实体类
@Data
public class Article {
private String articleId;
private String title;
private Integer authorId;
// 加入需要关联的实体类
private Author author;
// 需要关联的一对多的评论
private List<Remark> remarks;
}
- resultMap
<resultMap id="resultMap" type="Article">
<id property="articleId" column="article_id"/>
<result property="title" column="title"/>
<result property="authorId" column="author_id"/>
<association property="author">
<id property="id" column="id"/>
<result property="author" column="author"/>
</association>
<collection property="remarks" ofType="Remark">
<id column="id" property="id"/>
<result property="cont" column="cont"/>
<result property="articleId" column="article_id"/>
</collection>
</resultMap>
- SQL语句
<select id="selectOneToMany" resultMap="resultMap">
select a.author_id, a.title, a.article_id, b.id, b.author, c.cont
from article a join author b on a.author_id = b.id join remark c on c.article_id = a.article_id
where a.article_id = #{id};
</select>
- 查询结果
[Article(articleId=1, title=葵花宝典, authorId=1, author=Author(id=1, author=黄药师), remarks=[Remark(id=1, cont=良心教程, articleId=1)])]
除了使用resultMap + collection外,也可以在程序中进行多次查询。
(3)多对一
待补充。。。。
五、mybatis-config.xml 配置
1、属性(properties)
这些属性可以在外部进行配置,并可以进行动态替换。既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
mybatis-config.xml
<!--替换属性-->
<properties resource="database.properties"/>
<!-- <properties resource="org/mybatis/example/config.properties">-->
<!-- <property name="username" value="dev_user"/>-->
<!-- <property name="password" value="F2Fa3!33TYyg"/>-->
<!-- </properties>-->
<!--数据库环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
database.properties (注意,数据库名用中文报错)
driver = "com.mysql.cj.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"
username = "root"
password = "root"
2、类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写,例如:
- 单个别名分别配置:
<typeAliases>
<typeAlias alias="Author" type="com.example.Modle.Author"/>
<typeAlias alias="Blog" type="com.example.Modle.Blog"/>
</typeAliases>
- 扫描包整个model包
会使用包内 Bean 的首字母小写的非限定类名来作为它的别名,首字母大写也支持。有注解则优先使用注解
<typeAliases>
<typeAlias alias="User" type="org.example.model.User"/>
<package name="org.example.model"/>
</typeAliases>
- 注解:
@Alias("xxx")
@Alias("author")
public class Author{
...
}
配置完别名之后,才能将resultType="com.example.Modle.Author"
变为 resultType="Author"
3、设置(settings)
(1)驼峰命名转换
默认false,不进行转换。开启后将数据库字段的column_table与实体类的columnTable进行自动对应,这样查出来的数据才能赋给实体类。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
(2)日志打印
- STDOUT_LOGGING
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
- LOG4J
(3)字段为null时处理
默认false,当查询一条记录,某个字段为null时,是否调用映射对象的 setter(map 对象时为 put)方法,默认mybatis不会处理这一字段,也就是不会调用null赋值给返回的对象。
<settings>
<setting name="callSettersOnNulls" value="true"/>
</settings>
(4)返回null的处理
默认false,当查询到记录,但返回行的所有列
都是null时,MyBatis默认返回 null对象,而不会创建返回对象,当调用返回对象的方法时,容易导致空指针错误。
当开启这个设置时,MyBatis会创建返回对象,但对象是一个null实例,返回的实体类对象的所有属性都是null。
<settings>
<setting name="returnInstanceForEmptyRow" value="true"/>
</settings>
注意:如果表为空,或者根据条件查找不到记录,必定会返回null或空列表[]
上述设置只适用于,当mybatis查找到了表记录,但是返回的列全是null的时候。如果返回的列,不是全部为null,则会正常创建返回对象。
六、缓存
1、一级缓存:
默认开启,存在于SqlSession的生命周期中,什么是SqlSession的生命周期呢,简单的来说,只有同一个请求才会是同一个SqlSession,那么就是说只有同一个请求我查询第二次这个缓存才会生效。
2、二级缓存:
也称为全局缓存,存在于SqlSessionFactory 的生命周期中,可以理解为跨sqlSession;缓存是以namespace为单位的,不同namespace下的操作互不影响,但是在多人开发的环境下,我的不同的namespace完全是有可能操作同一张表的,那么会导致一个namespace的数据修改了一张表,但是另一个namespace的那张表的数据缓存没被修改,这样查询的数据就会错误。
- 开启方式:在Mapper.xml里添加
<cache/>
即可
七、使用注解开发
@select("select * frome user")
List<User> getUsers();
@select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Insert("insert into user(id,name,password) values(#{id},#{name},#{password})")
int addUser(User user);
@Update("update user set name=#{name},password=#{password} where id = #{id}")
int updateUser(User user);
@Delete("delete from user where id = #{id}")
int delete(@Param("uid") int id);
mybatis-config.xml
<!--注解没有xml文件,所以绑定Mapper接口-->
<mappers>
<mapper class="org.example.model.UserMapper"/>
</mappers>
八、Mybatis与Spring整合
待补充。。。。
九、Mybatis与SpringBoot整合
待补充。。。。