天天看点

springboot集成mybatis执行一个查询所有的操作使用map作为参数模糊查询生命周期复杂查询动态sql

springboot集成mybatis

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

执行一个查询所有的操作

包结构

springboot集成mybatis执行一个查询所有的操作使用map作为参数模糊查询生命周期复杂查询动态sql

引入依赖

在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>