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. AcWing 180. 排书

    AStar 最坏情况\(O(log_2560 ^ 4)\) 用\(AStar\)算法做了这题,程序跑了\(408ms\). 相比于\(IDA*\)的\(100ms\)左右要慢上不少. 且\(A*\)由 ...

  2. 电脑获取手机app内的scheme

    做app开发,有时需要跳转打开外部的app应用,来促成引流或者分享等,这个时候就需要通过scheme跳转协议来完成. 使用scheme跳转外部app,就需要配置对应app的scheme,那这个sche ...

  3. 最新快手抖音短视频源码web+APP架设教程+完整数据

    最新更新快手抖音短视频源码web+APP架设教程+完整数据完美运行 视频直播源码,好东西,反正有人要就是了. 下载地址:https://pan.baidu.com/wap/init?surl=POU5 ...

  4. 2020传智博黑马python课

      网上花钱买来的资源,免费分享给冷冷的兄弟们! 已经把相关网站广告后缀名全部替换修改,现在文件已经全部没有广告了, 不过就是课件的压缩包需要密码,已经在该文件夹说明,大家放心使用, 文件清爽,文件名 ...

  5. java-02-基础语法

    1.分支语句 if语句 格式 if(关系表达式1){语句1} else if(关系表达式2){语句2} else{语句3}; 说明 如果关系表达式1的值为true,执行语句1. 如果关系表达式2的值为 ...

  6. vue第十一单元(内置组件)

    第十一单元(内置组件) #课程目标 熟练掌握component组件的用法 熟练使用keep-alive组件 #知识点 #1.component组件 component是vue的一个内置组件,作用是:配 ...

  7. PHP面向对象的学习(封装,继承,多态)

    这个文章就是记录  巩固一下PHP的面向对象的部分 ,无非就是封装,继承,多态等等这几部分 这里参考了一位大佬总结的文章:https://www.cnblogs.com/adaia/p/6986576 ...

  8. hugging face-基于pytorch-bert的中文文本分类

    1.安装hugging face的transformers pip install transformers 2.下载相关文件 字表: wget http://52.216.242.246/model ...

  9. MySQL高可用方案-MySQL InnoDB Cluster

    MySQL InnoDB Cluster简介 MySQL InnoDB Cluster 是最新GA的MySQL高可用方案,利用MySQL Group Replication和MySQL Shell.M ...

  10. 网页客服思路以及QQ截图粘贴到聊天框功能

    功能: 1.客服需登录进入客服页面.用户无需登录,进入用户页面,直接获取sessionId作为id值. 2.用户进入页面并且发送消息时,客服才会获取到该用户,并在左侧列表显示. 3.点击用户名即可切换 ...