【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

(二)MyBatis从入门到入土——开发一个Mybatis项目

Java冢狐发布于 今天 04:28

这是mybatis系列第2篇。没看前文的建议先去【Java冢狐】公众号中查看前文,方便理解和掌握这篇文章主要接着前文介绍了如何创建并使用Mybatis。

实战演练

上一篇文章中我们大体介绍了MyBatis是如何使用的以及其内部的一些逻辑,也辅助了一些代码进行了讲解,下面我们就把这些代码写完,让整个程序运行起来。

准备数据库

mysql中运行下面脚本:创建一个数据库

/*创建数据库mybatisdemo*/

DROP DATABASE IF EXISTS `mybatisdemo`;

CREATE DATABASE `mybatisdemo`;

USE `mybatisdemo`;

/*创建表结构*/

DROP TABLE IF EXISTS `user`;

CREATE TABLE user (

id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键,用户id,自动增长',

`name` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '姓名',

`age` SMALLINT NOT NULL DEFAULT 1 COMMENT '年龄',

`salary` DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '薪水'

) COMMENT '用户表';

SELECT * FROM user;

实现的功能

基于user表,我们主要使用mybatis来演示以下几个功能

  • 通用的插入操作:支持动态插入。根据传入的字段的值,动态生成insert语句
  • 批量插入功能
  • 通用的更新操作:支持动态更新。根据传入的字段的值,动态生成update语句
  • 通用的查询操作:支持各种组合条件查询、分页、排序等各种复杂查询需求

创建maven项目

idea中创建maven项目,创建一个父项目mybatis-demo和一个子项目chat01,如下所示

项目结构

如下图:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

引入mybatis依赖

mybatis-demo/pom.xml内容如下:

 <properties>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<!-- 配置maven编译的时候采用的编译器版本 -->

<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>

<!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->

<maven.compiler.source>1.8</maven.compiler.source>

<!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->

<maven.compiler.target>1.8</maven.compiler.target>

<mybatis.version>3.5.3</mybatis.version>

<mysql.version>5.1.47</mysql.version>

<lombok.version>1.18.10</lombok.version>

</properties>

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>${mybatis.version}</version>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>${mysql.version}</version>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>${lombok.version}</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

<version>1.2.3</version>

</dependency>

</dependencies>

</dependencyManagement>

chat01/pom.xml内容如下:

    <dependencies>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

</dependency>

</dependencies>

上面我们引入了mybatis需要的包、mysql jdbc驱动、lombok、单元测试需要的junit包、日志输出需要的logback包。

配置logback

mybatis在运行过程中会输出一些日志,比如sql信息、sql的参数信息、执行的结果等信息,mybatis中会通过logback输出出来。

在chat01/src/main/resources目录中新建文件logback.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

<encoder>

<pattern>%d{mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>

</encoder>

</appender>

<logger name="zhonghu" level="debug" additivity="false">

<appender-ref ref="STDOUT" />

</logger>

</configuration>

创建mybatis相关文件

user.xml

chat01/src/main/resources目录中新建user.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">

<mapper namespace="zhonghu.mybatis.chat01.UserMapper">

<!-- 插入 -->

<insert id="insert" parameterType="zhonghu.mybatis.chat01.UserModel" keyProperty="id" useGeneratedKeys="true">

<![CDATA[ INSERT INTO `user` ]]>

<trim prefix="(" suffix=")" suffixOverrides=",">

<if test="id!=null">

<![CDATA[ `id`, ]]>

</if>

<if test="name!=null">

<![CDATA[ `name`, ]]>

</if>

<if test="age!=null">

<![CDATA[ `age`, ]]>

</if>

<if test="salary!=null">

<![CDATA[ `salary`, ]]>

</if>

</trim>

<![CDATA[ VALUES ]]>

<trim prefix="(" suffix=")" suffixOverrides=",">

<if test="id!=null">

<![CDATA[ #{id}, ]]>

</if>

<if test="name!=null">

<![CDATA[ #{name}, ]]>

</if>

<if test="age!=null">

<![CDATA[ #{age}, ]]>

</if>

<if test="salary!=null">

<![CDATA[ #{salary}, ]]>

</if>

</trim>

</insert>

<!-- 批量插入 -->

<insert id="insertBatch" parameterType="map">

<![CDATA[ INSERT INTO `user` (`id`, `name`, `age`, `salary`) VALUES ]]>

<foreach collection="list" separator="," item="item">

(#{item.id}, #{item.name}, #{item.age}, #{item.salary})

</foreach>

</insert>

<!-- 更新 -->

<update id="update" parameterType="zhonghu.mybatis.chat01.UserModel">

<![CDATA[ UPDATE `user` ]]>

<set>

<if test="name!=null">

<![CDATA[ `name` = #{name}, ]]>

</if>

<if test="age!=null">

<![CDATA[ `age` = #{age}, ]]>

</if>

<if test="salary!=null">

<![CDATA[ `salary` = #{salary}, ]]>

</if>

</set>

<where>

<if test="id!=null">

<![CDATA[ AND `id` = #{id} ]]>

</if>

</where>

</update>

<!-- 更新 -->

<update id="updateByMap" parameterType="map">

<![CDATA[ UPDATE `user` ]]>

<set>

<if test="name!=null">

<![CDATA[ `name` = #{name}, ]]>

</if>

<if test="age!=null">

<![CDATA[ `age` = #{age}, ]]>

</if>

<if test="salary!=null">

<![CDATA[ `salary` = #{salary}, ]]>

</if>

</set>

<where>

<if test="id!=null">

<![CDATA[ AND `id` = #{id} ]]>

</if>

</where>

</update>

<!-- 删除 -->

<delete id="delete" parameterType="map">

<![CDATA[

DELETE FROM `user`

]]>

<where>

<if test="id!=null">

<![CDATA[ AND `id` = #{id} ]]>

</if>

</where>

</delete>

<!-- 查询记录 -->

<select id="getModelList" parameterType="map" resultType="zhonghu.mybatis.chat01.UserModel">

<![CDATA[

SELECT

]]>

<choose>

<when test="tableColumnList!=null and tableColumnList.size() >= 1">

<foreach collection="tableColumnList" item="item" separator=",">

<![CDATA[ ${item} ]]>

</foreach>

</when>

<otherwise>

<![CDATA[

`id`,

`name`,

`age`,

`salary`

]]>

</otherwise>

</choose>

<![CDATA[

FROM

`user` a

]]>

<where>

<if test="id!=null and id.toString()!=''">

<![CDATA[ AND a.`id` = #{id} ]]>

</if>

<if test="idList!=null and idList.size() >= 1">

<![CDATA[ AND a.`id` IN ]]>

<foreach collection="idList" item="item" open="(" separator="," close=")">

<![CDATA[ #{item} ]]>

</foreach>

</if>

<if test="name!=null and name.toString()!=''">

<![CDATA[ AND a.`name` = #{name} ]]>

</if>

<if test="age!=null and age.toString()!=''">

<![CDATA[ AND a.`age` = #{age} ]]>

</if>

<if test="salary!=null and salary.toString()!=''">

<![CDATA[ AND a.`salary` = #{salary} ]]>

</if>

<if test="nameLike!=null and nameLike.toString()!=''">

<![CDATA[ AND a.`name` like '%${nameLike}%' ]]>

</if>

<if test="salaryGte!=null and salaryGte.toString()!=''">

<![CDATA[ AND a.`salary` >= #{salaryGte} ]]>

</if>

</where>

<if test="sort!=null and sort.toString()!=''">

<![CDATA[ order by ${sort} ]]>

</if>

<if test="skip!=null and pageSize!=null">

<![CDATA[ LIMIT #{skip},#{pageSize} ]]>

</if>

</select>

</mapper>

mybatis-config.xml

chat01/src/main/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>

<properties>

<property name="driver" value="com.mysql.jdbc.Driver"/>

<property name="url" value="jdbc:mysql://localhost:3306/mybatisdemo?characterEncoding=UTF-8"/>

<property name="username" value="root"/>

<property name="password" value="123456"/>

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

<mappers>

<mapper resource="mapper/user.xml"/>

</mappers>

</configuration>

UserMapper接口

package zhonghu.mybatis.chat01;

import java.util.List;

import java.util.Map;

public interface UserMapper {

/**

* 插入用户信息

*

* @param userModel

* @return

*/

void insert(UserModel userModel);

/**

* 批量插入用户信息

*

* @param userModelList

*/

void insertBatch(List<UserModel> userModelList);

/**

* 更新用户信息

*

* @param userModel

* @return

*/

int update(UserModel userModel);

/**

* 通过map来更新用户记录

*

* @param map

* @return

*/

int updateByMap(Map<String, Object> map);

/**

* 通过map来删除用户记录

*

* @param map

* @return

*/

int delete(Map<String, Object> map);

/**

* 查询用户列表

*

* @param map

* @return

*/

List<UserModel> getModelList(Map<String, Object> map);

}

UserModel类

package zhonghu.mybatis.chat01;

import lombok.*;

@Getter

@Setter

@NoArgsConstructor

@AllArgsConstructor

@Builder

@ToString

public class UserModel {

private Long id;

private String name;

private Integer age;

private Double salary;

}

UserUtil类

package zhonghu.mybatis.chat01;

import lombok.extern.slf4j.Slf4j;

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;

@Slf4j

public class UserUtil {

private static SqlSessionFactory sqlSessionFactory = build();

public static SqlSessionFactory build() {

try {

return new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));

} catch (IOException e) {

log.error(e.getMessage(), e);

throw new RuntimeException(e);

}

}

@FunctionalInterface

public interface SessionCall<O> {

O call(SqlSession session) throws Exception;

}

@FunctionalInterface

public interface MapperCall<T, O> {

O call(T mapper) throws Exception;

}

public static <T, O> O callMapper(Class<T> tClass, MapperCall<T, O> mapper) throws Exception {

return call(session -> mapper.call(session.getMapper(tClass)));

}

public static <O> O call(SessionCall<O> sessionCall) throws Exception {

try (SqlSession session = sqlSessionFactory.openSession(true);) {

return sessionCall.call(session);

}

}

}

创建单元测试类UserMapperTest

chat01\src\test\java\zhonghu\mybatis\chat01中创建UserMapperTest,代码如下:

package zhonghu.mybatis.chat01;

import lombok.extern.slf4j.Slf4j;

import org.junit.Test;

import java.util.*;

import java.util.stream.Collectors;

@Slf4j

public class UserMapperTest {

//动态插入

@Test

public void insert() throws Exception {

UserModel userModel1 = UserModel.builder().name("Java冢狐").build();

UserUtil.callMapper(UserMapper.class, mapper -> {

mapper.insert(userModel1);

return null;

});

log.info("插入结果:{}", this.getModelById(userModel1.getId()));

log.info("---------------------");

UserModel userModel2 = UserModel.builder().name("冢狐").age(23).salary(50000.00).build();

UserUtil.callMapper(UserMapper.class, mapper -> {

mapper.insert(userModel2);

return null;

});

log.info("插入结果:{}", this.getModelById(userModel2.getId()));

}

//批量插入

@Test

public void insertBatch() throws Exception {

List<UserModel> userModelList = new ArrayList<>();

for (int i = 1; i <= 5; i++) {

userModelList.add(UserModel.builder().name("Java冢狐-" + i).age(23 + i).salary(10000.00 * i).build());

userModelList.add(UserModel.builder().name("Mybatis-" + i).age(18 + i).salary(10000.00 * i).build());

}

UserUtil.callMapper(UserMapper.class, mapper -> {

mapper.insertBatch(userModelList);

return null;

});

List<UserModel> userModelList1 = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(null));

log.info("结果:{}", userModelList1);

}

//根据用户id删除数据

@Test

public void delete() throws Exception {

Map<String, Object> map = new HashMap<>();

//需要删除的用户id

map.put("id", 1);

Integer count = UserUtil.callMapper(UserMapper.class, mapper -> mapper.delete(map));

log.info("删除行数:{}", count);

}

//动态更新

@Test

public void update() throws Exception {

//将userId=2的name修改为:修改冢狐

Long userId1 = 2L;

Integer count = UserUtil.callMapper(UserMapper.class, mapper -> mapper.update(UserModel.builder().id(userId1).name("修改冢狐").build()));

log.info("更新行数:{}", count);

log.info("---------------------");

//将userId=3的name修改为:修改冢狐,薪水为:6666.66

Long userId2 = 3L;

count = UserUtil.callMapper(UserMapper.class, mapper -> mapper.update(UserModel.builder().id(userId2).name("修改冢狐").salary(6666.66D).build()));

log.info("更新行数:{}", count);

}

//按用户id查询

public UserModel getModelById(Long userId) throws Exception {

//查询指定id的数据

Map<String, Object> map = new HashMap<>();

map.put("id", userId);

return UserUtil.callMapper(UserMapper.class, mapper -> {

List<UserModel> userModelList = mapper.getModelList(map);

if (userModelList.size() == 1) {

return userModelList.get(0);

}

return null;

});

}

//查询所有数据

@Test

public void getModelList1() throws Exception {

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(null));

log.info("结果:{}", userModelList);

}

//查询多个用户id对应的数据

@Test

public void getModelListByIds() throws Exception {

List<Integer> idList = Arrays.asList(2, 3, 4).stream().collect(Collectors.toList());

Map<String, Object> map = new HashMap<>();

map.put("idList", idList);

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(map));

log.info("结果:{}", userModelList);

}

//多条件 & 指定返回的列

@Test

public void getModelList2() throws Exception {

//查询姓名中包含Java冢狐以及薪资大于3万的用户id、姓名

Map<String, Object> map = new HashMap<>();

map.put("nameLike", "Java冢狐");

map.put("salaryGte", 30000.00D);

//需要返回的列

List<String> tableColumnList = new ArrayList<>();

tableColumnList.add("id");

tableColumnList.add("name");

map.put("tableColumnList", tableColumnList);

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(map));

log.info("结果:{}", userModelList);

}

//条件过滤 & 排序 & 分页查询数据 & 只返回用户id、salary

@Test

public void getPage() throws Exception {

//查询姓名中包含Java冢狐以及薪资大于3万的用户id,按照薪资倒叙,每页5条取第1页

Map<String, Object> map = new HashMap<>();

map.put("nameLike", "Java冢狐");

map.put("salaryGte", 30000.00D);

//加入排序参数

map.put("sort", "salary desc");

//加入分页参数

int page = 1;

int pageSize = 5;

map.put("skip", (page - 1) * pageSize);

map.put("pageSize", pageSize);

//加入需要返回的列

List<String> tableColumnList = new ArrayList<>();

tableColumnList.add("id");

tableColumnList.add("salary");

map.put("tableColumnList", tableColumnList);

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(map));

log.info("结果:{}", userModelList);

}

}

项目最终结构如下

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:动态插入

运行动态插入,输出如下:

29:45.734 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==>  Preparing: INSERT INTO `user` ( `name` ) VALUES ( ? )

29:45.755 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==> Parameters: Java冢狐(String)

29:45.843 [main] DEBUG z.mybatis.chat01.UserMapper.insert - <== Updates: 1

29:45.859 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a WHERE a.`id` = ?

29:45.859 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 1(Long)

29:45.871 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 1

29:45.871 [main] INFO z.mybatis.chat01.UserMapperTest - 插入结果:UserModel(id=1, name=Java冢狐, age=1, salary=0.0)

29:45.873 [main] INFO z.mybatis.chat01.UserMapperTest - ---------------------

29:45.873 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==> Preparing: INSERT INTO `user` ( `name`, `age`, `salary` ) VALUES ( ?, ?, ? )

29:45.874 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==> Parameters: 冢狐(String), 23(Integer), 50000.0(Double)

29:46.081 [main] DEBUG z.mybatis.chat01.UserMapper.insert - <== Updates: 1

29:46.082 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a WHERE a.`id` = ?

29:46.082 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 2(Long)

29:46.083 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 1

29:46.083 [main] INFO z.mybatis.chat01.UserMapperTest - 插入结果:UserModel(id=2, name=冢狐, age=23, salary=50000.0)

  • 数据库数据变为:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

这个方法主要有4步操作:

  • 插入一条用户记录,用户记录只有name字段有值
  • 去db中查询步骤1中插入的记录
  • 插入一条用户记录,这次插入的记录所有字段都指定了值
  • 去db中查询步骤3中插入的记录

两次插入调用都是mapper.insert方法,传入的都是UserModel对象,唯一不同的是这个对象构建的时候字段的值不一样,最后再认真看一下上面输出的sql,产生的2个insert也是不一样的,这个mapper.insert方法可以根据UserModel对象字段是否有值来组装我们需要的sql,这就实现了动态插入

测试:批量插入

运行批量插入,输出如下:

33:49.134 [main] DEBUG z.m.chat01.UserMapper.insertBatch - ==>  Preparing: INSERT INTO `user` (`id`, `name`, `age`, `salary`) VALUES (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?)

33:49.155 [main] DEBUG z.m.chat01.UserMapper.insertBatch - ==> Parameters: null, Java冢狐-1(String), 24(Integer), 10000.0(Double), null, Mybatis-1(String), 19(Integer), 10000.0(Double), null, Java冢狐-2(String), 25(Integer), 20000.0(Double), null, Mybatis-2(String), 20(Integer), 20000.0(Double), null, Java冢狐-3(String), 26(Integer), 30000.0(Double), null, Mybatis-3(String), 21(Integer), 30000.0(Double), null, Java冢狐-4(String), 27(Integer), 40000.0(Double), null, Mybatis-4(String), 22(Integer), 40000.0(Double), null, Java冢狐-5(String), 28(Integer), 50000.0(Double), null, Mybatis-5(String), 23(Integer), 50000.0(Double)

33:49.378 [main] DEBUG z.m.chat01.UserMapper.insertBatch - <== Updates: 10

33:49.387 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a

33:49.387 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters:

33:49.397 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 12

33:49.397 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=1, name=Java冢狐, age=1, salary=0.0), UserModel(id=2, name=冢狐, age=23, salary=50000.0), UserModel(id=3, name=Java冢狐-1, age=24, salary=10000.0), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Java冢狐-2, age=25, salary=20000.0), UserModel(id=6, name=Mybatis-2, age=20, salary=20000.0), UserModel(id=7, name=Java冢狐-3, age=26, salary=30000.0), UserModel(id=8, name=Mybatis-3, age=21, salary=30000.0), UserModel(id=9, name=Java冢狐-4, age=27, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=40000.0), UserModel(id=11, name=Java冢狐-5, age=28, salary=50000.0), UserModel(id=12, name=Mybatis-5, age=23, salary=50000.0)]

这次批量插入了10条用户记录,可以看到有这样的输出:

33:49.378 [main] DEBUG z.m.chat01.UserMapper.insertBatch - <==    Updates: 10

上面这个表示插入影响的行数,10表示插入了10行。

批量插入之后,又执行了全表查询,这次插入了10条,加上前面的2个单条插入,表中总计12条记录。

  • 数据库数据变为:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:根据用户id删除数据

运行删除,输出如下:

44:52.064 [main] DEBUG z.mybatis.chat01.UserMapper.delete - ==>  Preparing: DELETE FROM `user` WHERE `id` = ?

44:52.083 [main] DEBUG z.mybatis.chat01.UserMapper.delete - ==> Parameters: 1(Integer)

44:52.383 [main] DEBUG z.mybatis.chat01.UserMapper.delete - <== Updates: 1

44:52.386 [main] INFO z.mybatis.chat01.UserMapperTest - 删除行数:1

  • 数据库结果如下:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:动态更新

运行动态更新代码,输出如下:

45:44.648 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==>  Preparing: UPDATE `user` SET `name` = ? WHERE `id` = ?

45:44.670 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==> Parameters: 修改冢狐(String), 2(Long)

45:44.788 [main] DEBUG z.mybatis.chat01.UserMapper.update - <== Updates: 1

45:44.790 [main] INFO z.mybatis.chat01.UserMapperTest - 更新行数:1

45:44.792 [main] INFO z.mybatis.chat01.UserMapperTest - ---------------------

45:44.793 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==> Preparing: UPDATE `user` SET `name` = ?, `salary` = ? WHERE `id` = ?

45:44.793 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==> Parameters: 修改冢狐(String), 6666.66(Double), 3(Long)

45:44.980 [main] DEBUG z.mybatis.chat01.UserMapper.update - <== Updates: 1

45:44.981 [main] INFO z.mybatis.chat01.UserMapperTest - 更新行数:1

2个更新,调用都是mapper.update方法,传入的都是UserModel类型的参数,只是2个UserModel对象的字段值不一样,最后产生的2个update语句也是不一样的,这个update语句是mybatis动态组装的,mybatis可以根据UserModel中字段是否为NULL,来拼装sql。

  • 数据库结果

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:动态查询

查询所有数据

运行查询有数据代码,输出如下:

46:56.345 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a

46:56.364 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters:

46:56.376 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 11

46:56.380 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=2, name=修改冢狐, age=23, salary=50000.0), UserModel(id=3, name=修改冢狐, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Java冢狐-2, age=25, salary=20000.0), UserModel(id=6, name=Mybatis-2, age=20, salary=20000.0), UserModel(id=7, name=Java冢狐-3, age=26, salary=30000.0), UserModel(id=8, name=Mybatis-3, age=21, salary=30000.0), UserModel(id=9, name=Java冢狐-4, age=27, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=40000.0), UserModel(id=11, name=Java冢狐-5, age=28, salary=50000.0), UserModel(id=12, name=Mybatis-5, age=23, salary=50000.0)]

可以看到sql是没有查询条件的。

查询多个用户id对应的数据

运行查询多个用户id对应数据,输出如下:

47:46.118 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a WHERE a.`id` IN ( ? , ? , ? )

47:46.139 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 2(Integer), 3(Integer), 4(Integer)

47:46.150 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 3

47:46.151 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=2, name=修改冢狐, age=23, salary=50000.0), UserModel(id=3, name=修改冢狐, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0)]

上面这个按照id列表查询也是比较常用的,比如我们在电商中查询订单列表,还需要查询每个订单对应的商品,此时可以先查询订单列表,然后在通过订单列表拿到所有的商品id集合,然后通过商品id集合去通过上面的方式检索商品信息,只需要2次查询就可以查询出订单及商品的信息了。

多条件 & 指定返回的列

运行多条件查询语句,查询姓名中包含Java冢狐以及薪资大于3万的用户id、姓名,输出如下:

48:34.925 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT id , name FROM `user` a WHERE a.`name` like '%Java冢狐%' AND a.`salary` >= ?

48:34.945 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 30000.0(Double)

48:34.955 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 3

48:34.955 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=7, name=Java冢狐-3, age=null, salary=null), UserModel(id=9, name=Java冢狐-4, age=null, salary=null), UserModel(id=11, name=Java冢狐-5, age=null, salary=null)]

看一下上面select语句,select后面只有id,name2个字段,where后面有多个条件,这种查询也是比较常用的,有些表可能有几十个字段,可能我们只需要几个字段,就可以使用上面这种查询。

条件过滤 & 排序 & 分页查询数据 & 只返回用户id、salary

运行分页查询,查询姓名中包含Java冢狐以及薪资大于3万的用户id,按照薪资倒叙,每页5条取第1页,输出如下:

49:03.709 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT id , salary FROM `user` a WHERE a.`name` like '%Java冢狐%' AND a.`salary` >= ? order by salary desc LIMIT ?,?

49:03.728 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 30000.0(Double), 0(Integer), 5(Integer)

49:03.739 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 3

49:03.740 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=11, name=null, age=null, salary=50000.0), UserModel(id=9, name=null, age=null, salary=40000.0), UserModel(id=7, name=null, age=null, salary=30000.0)]

大家主要看一下输出的sql,如下:

SELECT id , salary FROM `user` a WHERE a.`name` like '%Java冢狐%' AND a.`salary` >= ? order by salary desc LIMIT ?,?

这个sql会根据查询条件,自动构建出我们需要的sql,十分的方便和简洁

案例总结

上面列举的一些用例基本上包含了我们对db所需的大部分操作,动态sql处理方面体现的最为强劲,如果让我们自己写,我们需要写很多判断,而用mybatis这么简单就实现了,我们在java代码中没有看到一个判断拼接语句,而这些sql的判断拼接都在一个文件中:user.xml中,这个就是mybatis中核心的文件,我们需要写的sql及判断逻辑基本上都在这个xml中,大家可以认真去看一下这个xml文件。

最后

  • 如果觉得看完有收获,希望能关注一下,顺便给我点个赞,这将会是我更新的最大动力,感谢各位的支持
  • 欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
  • 求一键三连:点赞、转发、在看。
  • 如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。

——我是冢狐,和你一样热爱编程。

java

阅读 37发布于 今天 04:28

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

Java冢狐

4 声望

0 粉丝

0 条评论

得票时间

avatar

Java冢狐

4 声望

0 粉丝

宣传栏

这是mybatis系列第2篇。没看前文的建议先去【Java冢狐】公众号中查看前文,方便理解和掌握这篇文章主要接着前文介绍了如何创建并使用Mybatis。

实战演练

上一篇文章中我们大体介绍了MyBatis是如何使用的以及其内部的一些逻辑,也辅助了一些代码进行了讲解,下面我们就把这些代码写完,让整个程序运行起来。

准备数据库

mysql中运行下面脚本:创建一个数据库

/*创建数据库mybatisdemo*/

DROP DATABASE IF EXISTS `mybatisdemo`;

CREATE DATABASE `mybatisdemo`;

USE `mybatisdemo`;

/*创建表结构*/

DROP TABLE IF EXISTS `user`;

CREATE TABLE user (

id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键,用户id,自动增长',

`name` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '姓名',

`age` SMALLINT NOT NULL DEFAULT 1 COMMENT '年龄',

`salary` DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '薪水'

) COMMENT '用户表';

SELECT * FROM user;

实现的功能

基于user表,我们主要使用mybatis来演示以下几个功能

  • 通用的插入操作:支持动态插入。根据传入的字段的值,动态生成insert语句
  • 批量插入功能
  • 通用的更新操作:支持动态更新。根据传入的字段的值,动态生成update语句
  • 通用的查询操作:支持各种组合条件查询、分页、排序等各种复杂查询需求

创建maven项目

idea中创建maven项目,创建一个父项目mybatis-demo和一个子项目chat01,如下所示

项目结构

如下图:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

引入mybatis依赖

mybatis-demo/pom.xml内容如下:

 <properties>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<!-- 配置maven编译的时候采用的编译器版本 -->

<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>

<!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->

<maven.compiler.source>1.8</maven.compiler.source>

<!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->

<maven.compiler.target>1.8</maven.compiler.target>

<mybatis.version>3.5.3</mybatis.version>

<mysql.version>5.1.47</mysql.version>

<lombok.version>1.18.10</lombok.version>

</properties>

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>${mybatis.version}</version>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>${mysql.version}</version>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>${lombok.version}</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

<version>1.2.3</version>

</dependency>

</dependencies>

</dependencyManagement>

chat01/pom.xml内容如下:

    <dependencies>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

</dependency>

</dependencies>

上面我们引入了mybatis需要的包、mysql jdbc驱动、lombok、单元测试需要的junit包、日志输出需要的logback包。

配置logback

mybatis在运行过程中会输出一些日志,比如sql信息、sql的参数信息、执行的结果等信息,mybatis中会通过logback输出出来。

在chat01/src/main/resources目录中新建文件logback.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

<encoder>

<pattern>%d{mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>

</encoder>

</appender>

<logger name="zhonghu" level="debug" additivity="false">

<appender-ref ref="STDOUT" />

</logger>

</configuration>

创建mybatis相关文件

user.xml

chat01/src/main/resources目录中新建user.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">

<mapper namespace="zhonghu.mybatis.chat01.UserMapper">

<!-- 插入 -->

<insert id="insert" parameterType="zhonghu.mybatis.chat01.UserModel" keyProperty="id" useGeneratedKeys="true">

<![CDATA[ INSERT INTO `user` ]]>

<trim prefix="(" suffix=")" suffixOverrides=",">

<if test="id!=null">

<![CDATA[ `id`, ]]>

</if>

<if test="name!=null">

<![CDATA[ `name`, ]]>

</if>

<if test="age!=null">

<![CDATA[ `age`, ]]>

</if>

<if test="salary!=null">

<![CDATA[ `salary`, ]]>

</if>

</trim>

<![CDATA[ VALUES ]]>

<trim prefix="(" suffix=")" suffixOverrides=",">

<if test="id!=null">

<![CDATA[ #{id}, ]]>

</if>

<if test="name!=null">

<![CDATA[ #{name}, ]]>

</if>

<if test="age!=null">

<![CDATA[ #{age}, ]]>

</if>

<if test="salary!=null">

<![CDATA[ #{salary}, ]]>

</if>

</trim>

</insert>

<!-- 批量插入 -->

<insert id="insertBatch" parameterType="map">

<![CDATA[ INSERT INTO `user` (`id`, `name`, `age`, `salary`) VALUES ]]>

<foreach collection="list" separator="," item="item">

(#{item.id}, #{item.name}, #{item.age}, #{item.salary})

</foreach>

</insert>

<!-- 更新 -->

<update id="update" parameterType="zhonghu.mybatis.chat01.UserModel">

<![CDATA[ UPDATE `user` ]]>

<set>

<if test="name!=null">

<![CDATA[ `name` = #{name}, ]]>

</if>

<if test="age!=null">

<![CDATA[ `age` = #{age}, ]]>

</if>

<if test="salary!=null">

<![CDATA[ `salary` = #{salary}, ]]>

</if>

</set>

<where>

<if test="id!=null">

<![CDATA[ AND `id` = #{id} ]]>

</if>

</where>

</update>

<!-- 更新 -->

<update id="updateByMap" parameterType="map">

<![CDATA[ UPDATE `user` ]]>

<set>

<if test="name!=null">

<![CDATA[ `name` = #{name}, ]]>

</if>

<if test="age!=null">

<![CDATA[ `age` = #{age}, ]]>

</if>

<if test="salary!=null">

<![CDATA[ `salary` = #{salary}, ]]>

</if>

</set>

<where>

<if test="id!=null">

<![CDATA[ AND `id` = #{id} ]]>

</if>

</where>

</update>

<!-- 删除 -->

<delete id="delete" parameterType="map">

<![CDATA[

DELETE FROM `user`

]]>

<where>

<if test="id!=null">

<![CDATA[ AND `id` = #{id} ]]>

</if>

</where>

</delete>

<!-- 查询记录 -->

<select id="getModelList" parameterType="map" resultType="zhonghu.mybatis.chat01.UserModel">

<![CDATA[

SELECT

]]>

<choose>

<when test="tableColumnList!=null and tableColumnList.size() >= 1">

<foreach collection="tableColumnList" item="item" separator=",">

<![CDATA[ ${item} ]]>

</foreach>

</when>

<otherwise>

<![CDATA[

`id`,

`name`,

`age`,

`salary`

]]>

</otherwise>

</choose>

<![CDATA[

FROM

`user` a

]]>

<where>

<if test="id!=null and id.toString()!=''">

<![CDATA[ AND a.`id` = #{id} ]]>

</if>

<if test="idList!=null and idList.size() >= 1">

<![CDATA[ AND a.`id` IN ]]>

<foreach collection="idList" item="item" open="(" separator="," close=")">

<![CDATA[ #{item} ]]>

</foreach>

</if>

<if test="name!=null and name.toString()!=''">

<![CDATA[ AND a.`name` = #{name} ]]>

</if>

<if test="age!=null and age.toString()!=''">

<![CDATA[ AND a.`age` = #{age} ]]>

</if>

<if test="salary!=null and salary.toString()!=''">

<![CDATA[ AND a.`salary` = #{salary} ]]>

</if>

<if test="nameLike!=null and nameLike.toString()!=''">

<![CDATA[ AND a.`name` like '%${nameLike}%' ]]>

</if>

<if test="salaryGte!=null and salaryGte.toString()!=''">

<![CDATA[ AND a.`salary` >= #{salaryGte} ]]>

</if>

</where>

<if test="sort!=null and sort.toString()!=''">

<![CDATA[ order by ${sort} ]]>

</if>

<if test="skip!=null and pageSize!=null">

<![CDATA[ LIMIT #{skip},#{pageSize} ]]>

</if>

</select>

</mapper>

mybatis-config.xml

chat01/src/main/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>

<properties>

<property name="driver" value="com.mysql.jdbc.Driver"/>

<property name="url" value="jdbc:mysql://localhost:3306/mybatisdemo?characterEncoding=UTF-8"/>

<property name="username" value="root"/>

<property name="password" value="123456"/>

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

<mappers>

<mapper resource="mapper/user.xml"/>

</mappers>

</configuration>

UserMapper接口

package zhonghu.mybatis.chat01;

import java.util.List;

import java.util.Map;

public interface UserMapper {

/**

* 插入用户信息

*

* @param userModel

* @return

*/

void insert(UserModel userModel);

/**

* 批量插入用户信息

*

* @param userModelList

*/

void insertBatch(List<UserModel> userModelList);

/**

* 更新用户信息

*

* @param userModel

* @return

*/

int update(UserModel userModel);

/**

* 通过map来更新用户记录

*

* @param map

* @return

*/

int updateByMap(Map<String, Object> map);

/**

* 通过map来删除用户记录

*

* @param map

* @return

*/

int delete(Map<String, Object> map);

/**

* 查询用户列表

*

* @param map

* @return

*/

List<UserModel> getModelList(Map<String, Object> map);

}

UserModel类

package zhonghu.mybatis.chat01;

import lombok.*;

@Getter

@Setter

@NoArgsConstructor

@AllArgsConstructor

@Builder

@ToString

public class UserModel {

private Long id;

private String name;

private Integer age;

private Double salary;

}

UserUtil类

package zhonghu.mybatis.chat01;

import lombok.extern.slf4j.Slf4j;

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;

@Slf4j

public class UserUtil {

private static SqlSessionFactory sqlSessionFactory = build();

public static SqlSessionFactory build() {

try {

return new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));

} catch (IOException e) {

log.error(e.getMessage(), e);

throw new RuntimeException(e);

}

}

@FunctionalInterface

public interface SessionCall<O> {

O call(SqlSession session) throws Exception;

}

@FunctionalInterface

public interface MapperCall<T, O> {

O call(T mapper) throws Exception;

}

public static <T, O> O callMapper(Class<T> tClass, MapperCall<T, O> mapper) throws Exception {

return call(session -> mapper.call(session.getMapper(tClass)));

}

public static <O> O call(SessionCall<O> sessionCall) throws Exception {

try (SqlSession session = sqlSessionFactory.openSession(true);) {

return sessionCall.call(session);

}

}

}

创建单元测试类UserMapperTest

chat01\src\test\java\zhonghu\mybatis\chat01中创建UserMapperTest,代码如下:

package zhonghu.mybatis.chat01;

import lombok.extern.slf4j.Slf4j;

import org.junit.Test;

import java.util.*;

import java.util.stream.Collectors;

@Slf4j

public class UserMapperTest {

//动态插入

@Test

public void insert() throws Exception {

UserModel userModel1 = UserModel.builder().name("Java冢狐").build();

UserUtil.callMapper(UserMapper.class, mapper -> {

mapper.insert(userModel1);

return null;

});

log.info("插入结果:{}", this.getModelById(userModel1.getId()));

log.info("---------------------");

UserModel userModel2 = UserModel.builder().name("冢狐").age(23).salary(50000.00).build();

UserUtil.callMapper(UserMapper.class, mapper -> {

mapper.insert(userModel2);

return null;

});

log.info("插入结果:{}", this.getModelById(userModel2.getId()));

}

//批量插入

@Test

public void insertBatch() throws Exception {

List<UserModel> userModelList = new ArrayList<>();

for (int i = 1; i <= 5; i++) {

userModelList.add(UserModel.builder().name("Java冢狐-" + i).age(23 + i).salary(10000.00 * i).build());

userModelList.add(UserModel.builder().name("Mybatis-" + i).age(18 + i).salary(10000.00 * i).build());

}

UserUtil.callMapper(UserMapper.class, mapper -> {

mapper.insertBatch(userModelList);

return null;

});

List<UserModel> userModelList1 = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(null));

log.info("结果:{}", userModelList1);

}

//根据用户id删除数据

@Test

public void delete() throws Exception {

Map<String, Object> map = new HashMap<>();

//需要删除的用户id

map.put("id", 1);

Integer count = UserUtil.callMapper(UserMapper.class, mapper -> mapper.delete(map));

log.info("删除行数:{}", count);

}

//动态更新

@Test

public void update() throws Exception {

//将userId=2的name修改为:修改冢狐

Long userId1 = 2L;

Integer count = UserUtil.callMapper(UserMapper.class, mapper -> mapper.update(UserModel.builder().id(userId1).name("修改冢狐").build()));

log.info("更新行数:{}", count);

log.info("---------------------");

//将userId=3的name修改为:修改冢狐,薪水为:6666.66

Long userId2 = 3L;

count = UserUtil.callMapper(UserMapper.class, mapper -> mapper.update(UserModel.builder().id(userId2).name("修改冢狐").salary(6666.66D).build()));

log.info("更新行数:{}", count);

}

//按用户id查询

public UserModel getModelById(Long userId) throws Exception {

//查询指定id的数据

Map<String, Object> map = new HashMap<>();

map.put("id", userId);

return UserUtil.callMapper(UserMapper.class, mapper -> {

List<UserModel> userModelList = mapper.getModelList(map);

if (userModelList.size() == 1) {

return userModelList.get(0);

}

return null;

});

}

//查询所有数据

@Test

public void getModelList1() throws Exception {

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(null));

log.info("结果:{}", userModelList);

}

//查询多个用户id对应的数据

@Test

public void getModelListByIds() throws Exception {

List<Integer> idList = Arrays.asList(2, 3, 4).stream().collect(Collectors.toList());

Map<String, Object> map = new HashMap<>();

map.put("idList", idList);

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(map));

log.info("结果:{}", userModelList);

}

//多条件 & 指定返回的列

@Test

public void getModelList2() throws Exception {

//查询姓名中包含Java冢狐以及薪资大于3万的用户id、姓名

Map<String, Object> map = new HashMap<>();

map.put("nameLike", "Java冢狐");

map.put("salaryGte", 30000.00D);

//需要返回的列

List<String> tableColumnList = new ArrayList<>();

tableColumnList.add("id");

tableColumnList.add("name");

map.put("tableColumnList", tableColumnList);

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(map));

log.info("结果:{}", userModelList);

}

//条件过滤 & 排序 & 分页查询数据 & 只返回用户id、salary

@Test

public void getPage() throws Exception {

//查询姓名中包含Java冢狐以及薪资大于3万的用户id,按照薪资倒叙,每页5条取第1页

Map<String, Object> map = new HashMap<>();

map.put("nameLike", "Java冢狐");

map.put("salaryGte", 30000.00D);

//加入排序参数

map.put("sort", "salary desc");

//加入分页参数

int page = 1;

int pageSize = 5;

map.put("skip", (page - 1) * pageSize);

map.put("pageSize", pageSize);

//加入需要返回的列

List<String> tableColumnList = new ArrayList<>();

tableColumnList.add("id");

tableColumnList.add("salary");

map.put("tableColumnList", tableColumnList);

List<UserModel> userModelList = UserUtil.callMapper(UserMapper.class, mapper -> mapper.getModelList(map));

log.info("结果:{}", userModelList);

}

}

项目最终结构如下

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:动态插入

运行动态插入,输出如下:

29:45.734 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==>  Preparing: INSERT INTO `user` ( `name` ) VALUES ( ? )

29:45.755 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==> Parameters: Java冢狐(String)

29:45.843 [main] DEBUG z.mybatis.chat01.UserMapper.insert - <== Updates: 1

29:45.859 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a WHERE a.`id` = ?

29:45.859 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 1(Long)

29:45.871 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 1

29:45.871 [main] INFO z.mybatis.chat01.UserMapperTest - 插入结果:UserModel(id=1, name=Java冢狐, age=1, salary=0.0)

29:45.873 [main] INFO z.mybatis.chat01.UserMapperTest - ---------------------

29:45.873 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==> Preparing: INSERT INTO `user` ( `name`, `age`, `salary` ) VALUES ( ?, ?, ? )

29:45.874 [main] DEBUG z.mybatis.chat01.UserMapper.insert - ==> Parameters: 冢狐(String), 23(Integer), 50000.0(Double)

29:46.081 [main] DEBUG z.mybatis.chat01.UserMapper.insert - <== Updates: 1

29:46.082 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a WHERE a.`id` = ?

29:46.082 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 2(Long)

29:46.083 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 1

29:46.083 [main] INFO z.mybatis.chat01.UserMapperTest - 插入结果:UserModel(id=2, name=冢狐, age=23, salary=50000.0)

  • 数据库数据变为:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

这个方法主要有4步操作:

  • 插入一条用户记录,用户记录只有name字段有值
  • 去db中查询步骤1中插入的记录
  • 插入一条用户记录,这次插入的记录所有字段都指定了值
  • 去db中查询步骤3中插入的记录

两次插入调用都是mapper.insert方法,传入的都是UserModel对象,唯一不同的是这个对象构建的时候字段的值不一样,最后再认真看一下上面输出的sql,产生的2个insert也是不一样的,这个mapper.insert方法可以根据UserModel对象字段是否有值来组装我们需要的sql,这就实现了动态插入

测试:批量插入

运行批量插入,输出如下:

33:49.134 [main] DEBUG z.m.chat01.UserMapper.insertBatch - ==>  Preparing: INSERT INTO `user` (`id`, `name`, `age`, `salary`) VALUES (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?) , (?, ?, ?, ?)

33:49.155 [main] DEBUG z.m.chat01.UserMapper.insertBatch - ==> Parameters: null, Java冢狐-1(String), 24(Integer), 10000.0(Double), null, Mybatis-1(String), 19(Integer), 10000.0(Double), null, Java冢狐-2(String), 25(Integer), 20000.0(Double), null, Mybatis-2(String), 20(Integer), 20000.0(Double), null, Java冢狐-3(String), 26(Integer), 30000.0(Double), null, Mybatis-3(String), 21(Integer), 30000.0(Double), null, Java冢狐-4(String), 27(Integer), 40000.0(Double), null, Mybatis-4(String), 22(Integer), 40000.0(Double), null, Java冢狐-5(String), 28(Integer), 50000.0(Double), null, Mybatis-5(String), 23(Integer), 50000.0(Double)

33:49.378 [main] DEBUG z.m.chat01.UserMapper.insertBatch - <== Updates: 10

33:49.387 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a

33:49.387 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters:

33:49.397 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 12

33:49.397 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=1, name=Java冢狐, age=1, salary=0.0), UserModel(id=2, name=冢狐, age=23, salary=50000.0), UserModel(id=3, name=Java冢狐-1, age=24, salary=10000.0), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Java冢狐-2, age=25, salary=20000.0), UserModel(id=6, name=Mybatis-2, age=20, salary=20000.0), UserModel(id=7, name=Java冢狐-3, age=26, salary=30000.0), UserModel(id=8, name=Mybatis-3, age=21, salary=30000.0), UserModel(id=9, name=Java冢狐-4, age=27, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=40000.0), UserModel(id=11, name=Java冢狐-5, age=28, salary=50000.0), UserModel(id=12, name=Mybatis-5, age=23, salary=50000.0)]

这次批量插入了10条用户记录,可以看到有这样的输出:

33:49.378 [main] DEBUG z.m.chat01.UserMapper.insertBatch - <==    Updates: 10

上面这个表示插入影响的行数,10表示插入了10行。

批量插入之后,又执行了全表查询,这次插入了10条,加上前面的2个单条插入,表中总计12条记录。

  • 数据库数据变为:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:根据用户id删除数据

运行删除,输出如下:

44:52.064 [main] DEBUG z.mybatis.chat01.UserMapper.delete - ==>  Preparing: DELETE FROM `user` WHERE `id` = ?

44:52.083 [main] DEBUG z.mybatis.chat01.UserMapper.delete - ==> Parameters: 1(Integer)

44:52.383 [main] DEBUG z.mybatis.chat01.UserMapper.delete - <== Updates: 1

44:52.386 [main] INFO z.mybatis.chat01.UserMapperTest - 删除行数:1

  • 数据库结果如下:

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:动态更新

运行动态更新代码,输出如下:

45:44.648 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==>  Preparing: UPDATE `user` SET `name` = ? WHERE `id` = ?

45:44.670 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==> Parameters: 修改冢狐(String), 2(Long)

45:44.788 [main] DEBUG z.mybatis.chat01.UserMapper.update - <== Updates: 1

45:44.790 [main] INFO z.mybatis.chat01.UserMapperTest - 更新行数:1

45:44.792 [main] INFO z.mybatis.chat01.UserMapperTest - ---------------------

45:44.793 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==> Preparing: UPDATE `user` SET `name` = ?, `salary` = ? WHERE `id` = ?

45:44.793 [main] DEBUG z.mybatis.chat01.UserMapper.update - ==> Parameters: 修改冢狐(String), 6666.66(Double), 3(Long)

45:44.980 [main] DEBUG z.mybatis.chat01.UserMapper.update - <== Updates: 1

45:44.981 [main] INFO z.mybatis.chat01.UserMapperTest - 更新行数:1

2个更新,调用都是mapper.update方法,传入的都是UserModel类型的参数,只是2个UserModel对象的字段值不一样,最后产生的2个update语句也是不一样的,这个update语句是mybatis动态组装的,mybatis可以根据UserModel中字段是否为NULL,来拼装sql。

  • 数据库结果

【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目

测试:动态查询

查询所有数据

运行查询有数据代码,输出如下:

46:56.345 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a

46:56.364 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters:

46:56.376 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 11

46:56.380 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=2, name=修改冢狐, age=23, salary=50000.0), UserModel(id=3, name=修改冢狐, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Java冢狐-2, age=25, salary=20000.0), UserModel(id=6, name=Mybatis-2, age=20, salary=20000.0), UserModel(id=7, name=Java冢狐-3, age=26, salary=30000.0), UserModel(id=8, name=Mybatis-3, age=21, salary=30000.0), UserModel(id=9, name=Java冢狐-4, age=27, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=40000.0), UserModel(id=11, name=Java冢狐-5, age=28, salary=50000.0), UserModel(id=12, name=Mybatis-5, age=23, salary=50000.0)]

可以看到sql是没有查询条件的。

查询多个用户id对应的数据

运行查询多个用户id对应数据,输出如下:

47:46.118 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT `id`, `name`, `age`, `salary` FROM `user` a WHERE a.`id` IN ( ? , ? , ? )

47:46.139 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 2(Integer), 3(Integer), 4(Integer)

47:46.150 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 3

47:46.151 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=2, name=修改冢狐, age=23, salary=50000.0), UserModel(id=3, name=修改冢狐, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0)]

上面这个按照id列表查询也是比较常用的,比如我们在电商中查询订单列表,还需要查询每个订单对应的商品,此时可以先查询订单列表,然后在通过订单列表拿到所有的商品id集合,然后通过商品id集合去通过上面的方式检索商品信息,只需要2次查询就可以查询出订单及商品的信息了。

多条件 & 指定返回的列

运行多条件查询语句,查询姓名中包含Java冢狐以及薪资大于3万的用户id、姓名,输出如下:

48:34.925 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT id , name FROM `user` a WHERE a.`name` like '%Java冢狐%' AND a.`salary` >= ?

48:34.945 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 30000.0(Double)

48:34.955 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 3

48:34.955 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=7, name=Java冢狐-3, age=null, salary=null), UserModel(id=9, name=Java冢狐-4, age=null, salary=null), UserModel(id=11, name=Java冢狐-5, age=null, salary=null)]

看一下上面select语句,select后面只有id,name2个字段,where后面有多个条件,这种查询也是比较常用的,有些表可能有几十个字段,可能我们只需要几个字段,就可以使用上面这种查询。

条件过滤 & 排序 & 分页查询数据 & 只返回用户id、salary

运行分页查询,查询姓名中包含Java冢狐以及薪资大于3万的用户id,按照薪资倒叙,每页5条取第1页,输出如下:

49:03.709 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==>  Preparing: SELECT id , salary FROM `user` a WHERE a.`name` like '%Java冢狐%' AND a.`salary` >= ? order by salary desc LIMIT ?,?

49:03.728 [main] DEBUG z.m.chat01.UserMapper.getModelList - ==> Parameters: 30000.0(Double), 0(Integer), 5(Integer)

49:03.739 [main] DEBUG z.m.chat01.UserMapper.getModelList - <== Total: 3

49:03.740 [main] INFO z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=11, name=null, age=null, salary=50000.0), UserModel(id=9, name=null, age=null, salary=40000.0), UserModel(id=7, name=null, age=null, salary=30000.0)]

大家主要看一下输出的sql,如下:

SELECT id , salary FROM `user` a WHERE a.`name` like '%Java冢狐%' AND a.`salary` >= ? order by salary desc LIMIT ?,?

这个sql会根据查询条件,自动构建出我们需要的sql,十分的方便和简洁

案例总结

上面列举的一些用例基本上包含了我们对db所需的大部分操作,动态sql处理方面体现的最为强劲,如果让我们自己写,我们需要写很多判断,而用mybatis这么简单就实现了,我们在java代码中没有看到一个判断拼接语句,而这些sql的判断拼接都在一个文件中:user.xml中,这个就是mybatis中核心的文件,我们需要写的sql及判断逻辑基本上都在这个xml中,大家可以认真去看一下这个xml文件。

最后

  • 如果觉得看完有收获,希望能关注一下,顺便给我点个赞,这将会是我更新的最大动力,感谢各位的支持
  • 欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
  • 求一键三连:点赞、转发、在看。
  • 如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。

——我是冢狐,和你一样热爱编程。

以上是 【Java】(二)MyBatis从入门到入土——开发一个Mybatis项目 的全部内容, 来源链接: utcz.com/a/112843.html

回到顶部