MyBtis CRUD

文章源码

基于代理 DAO 的 CRUD

根据 ID 查询操作

在持久层接口中添加 findById 方法:

public interface UserDAO {

    /**
* 根据 ID 查询操作
* @param userId
* @return
*/
User findById(Integer userId);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<select id="findById" resultType="cn.parzulpan.domain.User" parameterType="java.lang.Integer">
select * from user where id = #{id};
</select>
</mapper>

注意

  • resultType 属性 指定结果集的类型
  • parameterType 属性 指定传入参数的类型
  • #{} 字符 它代表占位符,相当于原来 JDBC 的 ?,都是用于执行语句时替换实际的数据。具体的数据是由 #{} 里面的内容决定的。

在测试类添加测试:

package cn.parzulpan.test;

import cn.parzulpan.dao.UserDAO;
import cn.parzulpan.domain.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test; import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List; /**
* @Author : parzulpan
* @Time : 2020-12
* @Desc :
*/ public class MyBatisCRUDTest {
private InputStream is;
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
private SqlSessionFactory factory;
private SqlSession session;
private UserDAO userDAO; @Before
public void init() throws IOException {
is = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = builder.build(is);
session = factory.openSession();
userDAO = session.getMapper(UserDAO.class);
} @After
public void destroy() throws IOException {
session.commit(); // 事务提交
session.close();
is.close();
} @Test
public void findByIdTest() {
User user = userDAO.findById(41);
System.out.println(user);
}
}

用户保存操作

在持久层接口中添加 saveUser 方法:

public interface UserDAO {

    /**
* 用户保存操作
* @param user
* @return 影响数据库记录的条数
*/
int saveUser(User user);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<insert id="saveUser" parameterType="cn.parzulpan.domain.User">
# 扩展:新增用户 id 的返回值,在 insert 之后执行
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username, birthday, sex, address) values (#{username}, #{birthday}, #{sex}, #{address});
</insert>
</mapper>

注意

  • ognl 表达式 它是 apache 提供的一种表达式语言,全称是 Object Graphic Navigation Language(对象图导航语言):

    • 它是按照一定的语法格式来获取数据的,语法格式就是使用 #{对象.对象} 的方式
    • #{user.username} 它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用 getUsername() 把值取出来。但是在 parameterType 属性上指定了实体类名称,所以可以省略 user

      而直接写 username。

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void saveUserTest() {
User user = new User(null, "modify username", new Date(), "男", "Beijing");
System.out.println("save before: " + user); // User{id=null, ...}
int i = userDAO.saveUser(user);
System.out.println(i);
System.out.println("save after: " + user); // User{id=52, ...}
}
}

用户更新操作

在持久层接口中添加 updateUser 方法:

public interface UserDAO {

    /**
* 用户更新操作
* @param user
* @return 影响数据库记录的条数
*/
int updateUser(User user);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<update id="updateUser" parameterType="cn.parzulpan.domain.User">
update user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where id = #{id};
</update>
</mapper>

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void updateUserTest() {
User user = userDAO.findById(42);
user.setUsername("Tom Tim");
user.setAddress("瑞典");
int i = userDAO.updateUser(user);
System.out.println(i);
}
}

用户删除操作

在持久层接口中添加 deleteUser 方法:

public interface UserDAO {

    /**
* 用户删除操作
* @param userId
* @return 影响数据库记录的条数
*/
int deleteUser(Integer userId);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id};
</delete>
</mapper>

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void deleteUserTest() {
int i = userDAO.deleteUser(49);
System.out.println(i);
}
}

用户模糊查询操作

在持久层接口中添加 findByName 方法:

public interface UserDAO {

    /**
* 用户模糊查询操作
* @param username
* @return
*/
List<User> findByName(String username);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<!-- 模糊查询操作的第一种配置方式 -->
<!-- 实际执行语句 Preparing: select * from user where username like ?; -->
<!-- 这种方式,在传入字符串实参时,就需要给定模糊查询的标识% -->
<select id="findByName" resultType="cn.parzulpan.domain.User" parameterType="String">
select * from user where username like #{username};
</select>
</mapper>

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void findByNameTest() {
List<User> userList = userDAO.findByName("%Tim%");
userList.forEach(System.out::println);
}
}

模糊查询的另一种配置方式,推荐这种方式,在持久层接口中添加 findByNameV2 方法:

public interface UserDAO {

    /**
* 用户模糊查询操作
* @param username
* @return
*/
List<User> findByNameV2(String username);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<!--模糊查询操作的第二种配置方式-->
<!-- 实际执行语句 Preparing: select * from user where username like '%Tim%'; -->
<!-- 这种方式,在传入字符串实参时,就不需要给定模糊查询的标识% -->
<select id="findByNameV2" resultType="cn.parzulpan.domain.User" parameterType="String">
select * from user where username like '%${value}%';
</select>
</mapper>

注意

  • #{} 表示一个占位符号,实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{} 可以有效防止 sql 注入。 #{} 可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{} 括号中可以是 value 或其它名称。
  • ${} 表示拼接 Sql 串,将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${} 可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${} 括号中只能是 value。

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void findByNameV2Test() {
List<User> userList = userDAO.findByNameV2("Tim");
userList.forEach(System.out::println);
}
}

使用聚合函数查询

在持久层接口中添加 findTotal 方法:

public interface UserDAO {

    /**
* 使用聚合函数查询
* @return
*/
int findTotal();
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
</mapper>

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void findTotalTest() {
int total = userDAO.findTotal();
System.out.println(total);
}
}

MyBtis 参数深入

parameterType

parameterType 属性 指定传入参数的类型,该属性的取值可以是基本类型引用类型(例如 String ),还可以是实体类类型(例如 User ),同时也可以使用实体类的包装

基本类型 和 String 可以直接写类型名称,也可以使用 包名.类名 的方式。实体类类型,目前只能使用全限定类名。

究其原因,是 MyBatis 在加载时已经把常用的数据类型注册了别名,从而在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。

传递实体类包装对象

编写 QueryV:

package cn.parzulpan.domain;

import java.io.Serializable;

/**
* @Author : parzulpan
* @Time : 2020-12
* @Desc :
*/ public class QueryV implements Serializable {
private static final long serialVersionUID = 93481234250463743L;
private User user; public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
}
}

在持久层接口中添加 findByQueryV 方法:

public interface UserDAO {

    /**
* 根据 QueryV 中的条件查询用户
* @param v
* @return
*/
List<User> findByQueryV(QueryV v);
}

在用户的映射配置文件中配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
<!--由于 将 ${} parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换
所以,模糊查询操作的不能使用第二种配置方式-->
<select id="findByQueryV" resultType="cn.parzulpan.domain.User" parameterType="cn.parzulpan.domain.QueryV">
select * from user where username like #{user.username}; # user 是 QueryV 的属性
</select>
</mapper>

在测试类添加测试:

public class MyBatisCRUDTest {

    @Test
public void findByQueryVTest() {
User user = new User();
user.setUsername("%Tim%");
QueryV queryV = new QueryV();
queryV.setUser(user);
List<User> userList = userDAO.findByQueryV(queryV);
userList.forEach(System.out::println);
}
}

MyBtis 输出结果封装

resultType 配置结果类型

resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。

需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。例如我们的实体类此时必须是全限定类名。

同时,当是实体类名称是,还有一个要求实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。

如果不能保持一致,可以修改映射配置,使用别名查询

<mapper namespace="cn.parzulpan.dao.UserDAO">
<select id="findAll" resultType="cn.parzulpan.domain.User">
select * from user;
</select> <!-- 将上面的修改为 -->
<select id="findAll" resultType="cn.parzulpan.domain.User">
select id as userId, username as userName, birthday as userBirthday, sex as userSex, address as userAddress from user;
</select>
</mapper>

这种方式,执行效率更快,但是开发效率稍低。

resultMap 结果类型

如果查询很多,都使用别名的话写起来岂不是很麻烦?

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系,从而实现封装。

<mapper namespace="cn.parzulpan.dao.UserDAO">
<!-- 建立 User 实体和数据库表的对应关系
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的
-->
<resultMap type="cn.parzulpan.dao.User" id="userMap">
<!--
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
-->
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap> <select id="findAll" rresultMap="userMap">
select * from user;
</select>
</mapper>

这种方式,开发效率更快,但是执行效率稍低。

SqlMapConfig.xml 配置文件

配置内容

SqlMapConfig.xml 中配置的内容和顺序:

-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-mappers(映射器)
--mapper
--package

properties 属性

在使用 properties 标签配置时,可以采用两种方式指定属性配置。

typeAliases 类型别名

MyBatis 支持的默认别名,我们也可以采用自定义别名方式来开发。

<?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"> <!--Mybatis 的主配置文件-->
<configuration> <!-- 使用 typeAliases 配置别名,它只能配置 domain 中类的别名 -->
<typeAliases>
<!-- 单个别名定义,alias 指定别名,type 指定实体类全限定类名,当指定了别名就不区分大小了-->
<!-- <typeAlias alias="user" type="cn.parzulpan.domain.User"/>-->
<!-- 批量别名定义,扫描整个包下的类,别名为类名,不区分大小-->
<package name="cn.parzulpan.domain"/>
</typeAliases> </configuration>
<?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="cn.parzulpan.dao.UserDAO">
<select id="findAll" resultType="user">
select * from user;
</select> <select id="findById" resultType="USER" parameterType="java.lang.Integer">
select * from user where id = #{id};
</select> <insert id="saveUser" parameterType="cn.parzulpan.domain.User">
# 扩展:新增用户 id 的返回值,在 insert 之后执行
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username, birthday, sex, address) values (#{username}, #{birthday}, #{sex}, #{address});
</insert> </mapper>

mappers 映射器

<?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"> <!--Mybatis 的主配置文件-->
<configuration>
<!--告知 MyBatis 映射配置的位置-->
<mappers>
<!-- XML 方式-->
<!-- 使用相对于类路径的资源 -->
<!-- <mapper resource="cn/parzulpan/dao/UserDAO.xml"/>--> <!--指定被注解的 DAO 全限定类名-->
<!-- 使用 mapper 接口类路径 -->
<!-- 此种方法要求 mapper 接口名称 和 mapper 映射文件名称 相同,且放在同一个目录中 -->
<!-- <mapper class="cn.parzulpan.dao.UserDAO"/>--> <!-- 使用 package 标签,用于指定 DAO 接口所在的包,指定之后就不许写 mapper 以及 resource 或 class 了 -->
<!-- 此种方法要求 mapper 接口名称 和 mapper 映射文件名称 相同,且放在同一个目录中 -->
<package name="cn.parzulpan.dao"/>
</mappers>
</configuration>

练习和总结

推荐观看代理 DAO 的执行过程

【MyBatis】MyBatis CRUD的更多相关文章

  1. 【转】MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作

    [转]MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作 上一篇博文MyBatis学习总结(一)——MyBatis快速入门中我们讲了如何使用Mybatis查询users表中的数据, ...

  2. 【Mybatis】MyBatis对表执行CRUD操作(三)

    本例在[Mybatis]MyBatis配置文件的使用(二)基础上继续学习对表执行CRUD操作 使用MyBatis对表执行CRUD操作 1.定义sql映射xml文件(EmployeeMapper.xml ...

  3. 【Mybatis】MyBatis之动态SQL(六)

    MyBatis 的强大特性之一便是它的动态 SQL,本章介绍动态 SQL 查看本章,请先阅读[Mybatis]MyBatis对表执行CRUD操作(三). 本例表结构 CREATE TABLE `emp ...

  4. 【Mybatis】MyBatis之Sql配置文件的使用(四)

    上一章[Mybatis]MyBatis对表执行CRUD操作(三),已经讲了基本操作,本章介绍Sql配置文件中常用功能 1.插入返回主键 2.参数值的获取方式 3.resultMap使用 插入返回主键 ...

  5. 【转】MyBatis学习总结(七)——Mybatis缓存

    [转]MyBatis学习总结(七)——Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualC ...

  6. 【转】MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突

    [转]MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突 在平时的开发中,我们表中的字段名和表对应实体类的属性名称不一定都是完全相同的,下面来演示一下这种情况下的如何解决字段名与实体 ...

  7. 【转】MyBatis学习总结(三)——优化MyBatis配置文件中的配置

    [转]MyBatis学习总结(三)——优化MyBatis配置文件中的配置 一.连接数据库的配置单独放在一个properties文件中 之前,我们是直接将数据库的连接配置信息写在了MyBatis的con ...

  8. 【转】MyBatis学习总结(一)——MyBatis快速入门

    [转]MyBatis学习总结(一)——MyBatis快速入门 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC ...

  9. 【Mybatis】MyBatis配置文件的使用(二)

    本例在[Mybatis]MyBatis快速入门(一)基础上继续学习XML映射配置文件 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properti ...

  10. 【Mybatis】MyBatis之配置自定义数据源(十一)

    本例是在[Mybatis]MyBatis之配置多数据源(十)的基础上进行拓展,查看本例请先学习第十章 实现原理 1.扩展Spring的AbstractRoutingDataSource抽象类(该类充当 ...

随机推荐

  1. 从.NET转GO了

    前言 近几个月刚从.NET转到GO,入职了一个使用GO微服务的互联网公司.因为需要熟悉公司的微服务架构和适应新公司的节奏,所以最近没时间写博客,现在简单做个总结. 转GO的经历 自学GO 上一年的八月 ...

  2. uniapp图片转base64

    直接上代码了,网上也很多一样的,这里记录下,因为仅仅第二种在真机微信小程序上我这里测试转换失败,所以就一并写在这里了: //图片转base64 urlTobase64(url){ // #ifdef ...

  3. Java-静态关键字Static&静态代码块

    静态成员变量:(static修饰变量) 如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类.多个对象共享同一份数据. 静态方法:(static修饰方法) 一旦使用 ...

  4. MobaXterm无法退格删除

    MobaXterm退格删除出现^H,总是要取消输入重新敲语句,很麻烦 解决方法:打开MobaXterm-->settings-->Configuration,把"Backspac ...

  5. G1 收集器

    基础知识 性能指标 在调优Java应用程序时,重点通常放在两个主要目标上:响应性 或 吞吐量. 响应性Responsiveness 是指应用程序对请求的数据做出响应的速度: 桌面用户界面对事件的响应速 ...

  6. Python高级语法-多继承MRO相关-args和kwargs(4.5.2)

    @ 目录 1.说明 2.代码 关于作者 1.说明 args数据类型为元组 kwargs数据类型为字典 一般传入方法中使用遍历去得到值 这个传入参数的顺序没有特殊的要求 当你自定义的参数传完以后,写了名 ...

  7. centos8中的MySQL卸载和安装

    centos8中的MySQL卸载和安装 前言 前几天在自己的服务器上安装了一个NDB集群[而且还没有成功] 放弃治疗后用一台没有mysql的服务器实现了单机版本的集群. 本来以为这事到这就结束了,结果 ...

  8. VS中使用RDLC提示类型不一致

    问题描述 错误"基类包括字段"XXXXXXX",但其类型(Microsoft.Reporting.WebForms.ReportViewer)与控件(Microsoft. ...

  9. 如何在iOS设备中配置S/MIME邮件签名证书

    本篇将介绍如何在iOS设备(如iPhone或iPad)上导入.配置并使用S/MIME邮件证书. 前置条件: iOS设备上已完成邮箱账号配置: 您的S/MIME邮件证书PFX/P12文件已导出备用. 步 ...

  10. 【PY从0到1】第六节 用户输入while循环

    # 6 第六节 用户输入while循环 # 1> 重要的函数--input() # 我们先讲解一下input():当Python碰到input()后会执行括号内的语句. # 随后等待用户的输入. ...