springboot集成mybatis
- 执行一个查询所有的操作
-
- 引入依赖
- 编写配置文件
- UserMapper文件及其实现类
- 实体类属性名
- 测试结果
- 使用map作为参数
- 模糊查询
- 生命周期
- 复杂查询
-
- 表设计
- 多对一关联查询
-
- 使用嵌套查询
- 使用结果嵌套
- 一对多关联查询
-
- 结果嵌套
- 嵌套子查询
- 动态sql
-
- 使用where标签
- 使用set标签
- 使用sql片段
- 使用foreach标签
执行一个查询所有的操作
包结构

引入依赖
在springboot集成mybaits中,我们需要引入mysql驱动,mybaits等相关依赖.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
编写配置文件
在application.yml中编写msql配置,及mybaits配置.
spring:
datasource:
password: 123456
username: root
url: jdbc:mysql://121.40.46.92:3306/mysql?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml #指定Mapper文件位置
type-aliases-package: com.junior.boot_mybaits.entity #指定实体类位置
config-location: classpath:mybaits-config/mybatis-config.xml #指定配置xml文件的位置
还可以创建一个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>
<typeAliases>
<!--定义别名,避免写全限定类名-->
<typeAlias alias="Integer" type="java.lang.Integer" />
<typeAlias alias="Long" type="java.lang.Long" />
<typeAlias alias="HashMap" type="java.util.HashMap" />
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
<typeAlias alias="ArrayList" type="java.util.ArrayList" />
<typeAlias alias="LinkedList" type="java.util.LinkedList" />
<typeAlias alias="User" type="com.junior.boot_mybaits.entity.User" />
</typeAliases>
</configuration>
UserMapper文件及其实现类
使用mybaits可以通过注解或者xml来写sql语句.我这里是通过xml方式来写sql语句.
<?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">
<mapper namespace="com.junior.boot_mybaits.mapper.UserMapper"> <!-- 命名空间,需要指定到它的实现接口 -->
<!-- id指定为实现类中的方法名,返回类型需要全路径指定包名 -->
<select id="getAll" resultType="com.junior.boot_mybaits.entity.User">
select * from users;
</select>
</mapper>
实现类
package com.junior.boot_mybaits.mapper;
import com.junior.boot_mybaits.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
List<User> getAll();
}
实体类属性名
尽量使属性名和数据库中的字段名保持一致,如果不一致将导致不一样的那个字段查不到数据.此时可以通过指定一个resultMap,在resultMap中将数据库字段与实体类的属性名匹配起来。
<resultMap id="userMap" type="User"> id与resultMap匹配, type使用实体类名(User已经使用别名代替)
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="passwore" property="password"/>
</resultMap>
<select id="getAll" resultMap="userMap"> 返回类型指定为resultMap
select * from users;
</select>
测试结果
@SpringBootTest
class BootMybaitsApplicationTests {
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.getAll();
for (User user : users){
System.out.println(user);
}
}
}
//User(id=1, name=zhangsan, password=null)
//User(id=2, name=lisi, password=null)
使用map作为参数
在实体类或者数据库字段名过多的时候,我们应该使用map来简化操作.
在UserMapper接口中定义
在UserMapper.xml中实现
<!-- 使用map作为参数-->
<update id="updataByMap" parameterType="map">
update users set passwore=#{password} where id=#{id}
</update>
测试
@Test
void updataByMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("id",2);
map.put("password",123456);
userMapper.updataByMap(map);
}
模糊查询
模糊查询参数需要带上通配符.
在UserMapper接口中定义
在UserMapper.xml中实现
<select id="getByLike" parameterType="string" resultType="User">
select * from users where name like #{name} //不要使用字符串拼接,容易被sql注入
</select>
测试
@Test
void getByLike(){
List<User> users = userMapper.getByLike("%小%"); //参数使用通配符
for (User user : users) {
System.out.println(user);
}
}
生命周期
SqlSessionFactoryBuilder:
- 一旦创建了SqlSessionFactory,就不需要了.
- 局部变量
SqlSessionFactory:
- 数据库连接池,
- 一旦被创建就应该在应用的运行期间就一直存在,没有理由丢弃它或者重建一个新的实例.
- 作用域应该为应用作用域
- 使用单例模式或者静态单例模式.
SqlSession:
- 连接到连接池的一个请求.
- SqlSession实例不是线程安全的,不能被共享,它的最佳作用域是请求或方法作用域.
- 请求结束需要关闭.
复杂查询
表设计
create table teacher(
id int(20) not null auto_increment,
name varchar(20) not null ,
primary key (id)
)ENGINE=innodb default charset =utf8;
insert into teacher (name) value ('李老师');
create table student(
id int(20) not null auto_increment,
name varchar(20) default null ,
tid int(20) default null,
primary key (id)
)ENGINE = innodb default charset = utf8;
insert into student (name, tid) VALUES ('小明',1);
insert into student (name, tid) VALUES ('小红',1);
insert into student (name, tid) VALUES ('小赵',1);
insert into student (name, tid) VALUES ('张三',1);
insert into student (name, tid) VALUES ('小白',1);
insert into student (name, tid) VALUES ('小紫',1);
多对一关联查询
实体类student(多个学生去关联一个老师)
public class Student {
private int id;
private String name;
private Teacher tid; // 属性指定为老师对象
}
实体类teacher
public class Teacher {
private int id;
private String name;
}
使用嵌套查询
在Mapper.xml文件中,
<!-- 关联查询 1 嵌套查询-->
<select id="findAllSt" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="com.junior.mybatis.entity.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
// 多对一以及一对一,使用association关联一个对象。一对多、多对多使用collection集合
<association property="tid" column="tid" javaType="com.junior.mybatis.entity.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="com.junior.mybatis.entity.Teacher">
select * from teacher where id = #{tid} //列tid的值作为参数
</select>
实现类
测试结果
Student(id=1, name=小明, tid=Teacher(id=1, name=张老师))
Student(id=2, name=小红, tid=Teacher(id=1, name=张老师))
Student(id=3, name=小赵, tid=Teacher(id=1, name=张老师))
Student(id=4, name=张三, tid=Teacher(id=1, name=张老师))
Student(id=5, name=小白, tid=Teacher(id=1, name=张老师))
Student(id=6, name=小紫, tid=Teacher(id=1, name=张老师))
使用结果嵌套
在Mapper.xml文件中,
<!-- 关联查询 2 嵌套结果-->
<resultMap id="StudentTeacher2" type="com.junior.mybatis.entity.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="tid" javaType="com.junior.mybatis.entity.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="findAllSt2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.id tid,t.name tname from student s, teacher t where t.id = s.tid
</select>
实现类
测试结果
Student(id=1, name=小明, tid=Teacher(id=1, name=张老师))
Student(id=2, name=小红, tid=Teacher(id=1, name=张老师))
Student(id=3, name=小赵, tid=Teacher(id=1, name=张老师))
Student(id=4, name=张三, tid=Teacher(id=1, name=张老师))
Student(id=5, name=小白, tid=Teacher(id=1, name=张老师))
Student(id=6, name=小紫, tid=Teacher(id=1, name=张老师))
一对多关联查询
实体类student
public class Student {
private int id;
private String name;
private int tid;
}
实体类teacher
public class Teacher {
private int id;
private String name;
private List<Student> students;
}
结果嵌套
<!-- 结果嵌套-->
<select id="findTeacher" resultMap="TeacherStudent">
select t.id tid, t.name tname, s.name sname from student s, teacher t where t.id = s.tid and t.id = #{id}
</select>
<resultMap id="TeacherStudent" type="com.junior.mybatis.entity.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 集合使用collection 集合中的泛型使用oftype指定-->
<collection property="students" ofType="com.junior.mybatis.entity.Student">
<result property="name" column="sname"/>
</collection>
</resultMap>
实现类
测试
Teacher(id=1, name=张老师, students=[Student(id=0, name=小明, tid=0), Student(id=0, name=小红, tid=0), Student(id=0, name=小赵, tid=0), Student(id=0, name=张三, tid=0), Student(id=0, name=小白, tid=0), Student(id=0, name=小紫, tid=0)])
嵌套子查询
<!-- 嵌套查询-->
<select id="findTeacher1" resultMap="TeacherStudent2">
select * from teacher where id=#{id}
</select>
<resultMap id="TeacherStudent2" type="com.junior.mybatis.entity.Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- column作为子查询的参数-->
<collection property="students" ofType="com.junior.mybatis.entity.Student" column="id" select="tostudent"/>
</resultMap>
<select id="tostudent" resultType="com.junior.mybatis.entity.Student">
select * from student where tid = #{id}
</select>
实现类
// 查询老师名下的所有学生(一对多 使用嵌套查询)
Teacher findTeacher1(int id);
测试类
@Test
void findTeacher1(){
Teacher teacher1 = studentMapper.findTeacher1(1);
System.out.println(teacher1);
}
动态sql
使用where标签
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
实体类
public class Blog {
private int id;
private String title;
private String author;
private Date createTime;
private int views;
}
Mapper.xml
<select id="findByWhere" parameterType="map" resultMap="BlogMap">
select * from blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
<if test="views != null">
and views > #{views}
</if>
</where>
=================== 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。==========
<trim prefix="where" prefixOverrides="and | or">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
<if test="views != null">
and views > #{views}
</if>
</trim>
</select>
<resultMap id="BlogMap" type="com.junior.mybatis.entity.Blog">
<result property="id" column="id"/>
<result property="title" column="title"/>
<result property="author" column="author"/>
<result property="createTime" column="create_time"/>
<result property="views" column="views"/>
</resultMap>
Mapper实现
测试类
@Test
void findByWhere(){
HashMap<String, Object> map = new HashMap<>();
// map.put("title","卖火柴的小女孩");
map.put("author","安徒生");
map.put("views",200);
List<Blog> blogs = blogMapper.findByWhere(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
}
使用set标签
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
Mapper.xml
<update id="updataBySet" parameterType="map">
update blog
<!-- <set>-->
<!-- <if test="title != null">-->
<!-- title = #{title}-->
<!-- </if>-->
<!-- <if test="author" >-->
<!-- author = #{author}-->
<!-- </if>-->
<!-- <if test="views">-->
<!-- views = #{views}-->
<!-- </if>-->
<!-- </set>-->
-- 自定义set
<trim prefix="set" suffixOverrides=",">
<if test="title != null">
title = #{title}
</if>
<if test="author != null" >
author = #{author}
</if>
<if test="views != null">
views = #{views}
</if>
</trim>
where id = #{id}
</update>
实现类
测试类
@Test
void updataBySet(){
HashMap<String , Object> map = new HashMap<>();
map.put("id",2);
map.put("views",229);
blogMapper.updataBySet(map);
}
使用sql片段
sql片段就是将重复的部分抽取出来,用来简化代码量。
将上面set部分的if判断抽取出来,单独使用sql标签
<sql id="set-title-author-views">
<if test="title != null">
title = #{title}
</if>
<if test="author != null" >
author = #{author}
</if>
<if test="views != null">
views = #{views}
</if>
</sql>
简化后的mapper.xml
<update id="updataBySet" parameterType="map">
update blog
<trim prefix="set" suffixOverrides=",">
<include refid="set-title-author-views"></include>
</trim>
where id = #{id}
</update>
使用foreach标签
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
在select in 查询多条数据时使用foreach
Mapper.xml
<!-- 在 sql in 条件后面使用foreach 参数为一个map -->
<select id="findByForeach" parameterType="map" resultMap="BlogMap">
select * from blog
<where>
title in
<foreach collection="titles" item="title" open="(" close=")" separator=",">
#{title}
</foreach>
</where>
</select>
实现类
// 使用foreach查询
List<Blog> findByForeach(Map<String,Object> map);
测试
@Test
void findByForeach(){
HashMap<String, Object> map = new HashMap<>();
ArrayList<String > list = new ArrayList<>();
list.add("拇指姑娘");
list.add("玩具店的夜");
map.put("titles",list);
List<Blog> blogs = blogMapper.findByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
}
批量插入
Mapper.xml
<!--批量插入 参数为list,类型为blog类-->
<insert id="insertByForeach" parameterType="list" >
insert into blog (title, author, create_time, views ) values
<foreach collection="list" item="blog" separator=",">
(#{blog.title},#{blog.author}, #{blog.createTime},#{blog.views})
</foreach>
</insert>
实现类
// 使用foreach 批量插入
void insertByForeach(List<Blog> list);
测试
@Test
void insertByForeach(){
List<Blog> blogs = new ArrayList<>();
Blog blog1 = new Blog(1,"小贝流浪记","孙幼军",new Date(),258);
Blog blog2 = new Blog(1,"小布头奇遇记","孙幼军",new Date(),687);
blogs.add(blog1);
blogs.add(blog2);
blogMapper.insertByForeach(blogs);
}
批量更新
多字段批量更新使用case语句
UPDATE categories
SET dingdan = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN ‘New Title 1’
WHEN 2 THEN ‘New Title 2’
WHEN 3 THEN ‘New Title 3’
END
WHERE id IN (1,2,3)
Mapper.xml
<!-- 批量更新 使用updata-->
<update id="updataByForeach" parameterType="list">
update blog
<set>
title =
<foreach collection="list" item="blog" separator=" " open="case id" close="end">
when #{blog.id} then #{blog.title}
</foreach>
--注意添加逗号(set竟然不能动态添加)
,views =
<foreach collection="list" item="blog" separator=" " open="case id" close="end">
when #{blog.id} then #{blog.views}
</foreach>
</set>
<where>
id in
<foreach collection="list" item="blog" separator="," open="(" close=")">
#{blog.id}
</foreach>
</where>
</update>