MyBatis的基本使用及常见问题
MyBatis
- 前言
- MyBatis简介
- MyBatis快速上手
- Mapper代理开发
- 增删改查
- 环境准备
- 配置文件完成增删改查
- 查询
- 添加
- 修改
- 删除
- 参数传递
- 注解完成增删改查
前言
JavaWeb

JavaWeb是用Java技术来解决相关Web互联网领域的技术栈。
MySQL数据库与SQL语言
MySQL:开源的中小型数据库。
MySQL登录:进入bin文件目录下以管理员身份cmd进去,net start mysql启动MySQL服务,net stop mysql停止服务,mysql -uroot -p进入登录页面,exit或者quit退出MySQL界面。
MySQL是一种关系型数据库管理软件,关系型数据库是建立在关系模型基础上的数据库,简单来说,关系型数据库是由多张能相互连接的二维表组成的数据库。
MyBatis简介
MyBatis是一款优秀的持久层框架,用于简化JDBC开发。
MyBatis免除几乎所有的JDBC代码以及设置参数和获取结果集的工作。
持久层
- 持久层是负责将数据保存到数据库的的那一层代码。
- JavaEE三层架构:表现层(页面展示)、业务层(逻辑处理)、持久层(数据持久化)。
MyBatis快速上手
需求
描述:查询user表中所有数据
步骤
1.创建user表,添加数据


2.创建模块,导入坐标
如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:
<!--mybatis依赖-->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version>
</dependency>
参考文档:MyBatis中文网
除了mybatis依赖,还需要mysql驱动、junit单元测试等坐标信息:
<!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><!--junit 单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version><scope>test</scope></dependency><!--添加slf4j日志api--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.20</version></dependency><!--添加logback-classic依赖--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><!--添加logback-core依赖--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version></dependency>
并在resources资源文件下导入logback.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--CONSOLE :表示当前的日志信息是可以输出到控制台的。--><appender name="Console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>[%level] %cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern></encoder></appender><logger name="com.wmy" level="DEBUG" additivity="false"><appender-ref ref="Console"/></logger><!--level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 默认debug<root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。--><root level="DEBUG"><appender-ref ref="Console"/></root>
</configuration>
3.编写MyBatis核心配置文件 --> 替换连接信息,解决硬编码问题
/resources/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><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><!--加载当前sql映射文件的路径 看下一步 替换为UserMapper.xml--><mapper resource="org/mybatis/example/BlogMapper.xml"/></mappers>
</configuration>
4.编写SQL映射文件 --> 统一管理sql语句,解决硬编码问题
/resources/com.wmy.Mapper/UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间
-->
<mapper namespace="test"><!--查询语句 id是唯一标识 resultType是返回类型 也就是User类 需要创建在pojo文件夹下的User类 里边的属性要和数据表中的对应--><select id="selectAll" resultType="com.wmy.reggie.pojo.User">select * from tb_user;</select>
</mapper>
5.编码
(1)定义POJO类
/java/com.wmy.pojo/User.java
public class User {private Integer id;private String username;private String password;private String gender;private String addr;public void setId(Integer id) {this.id = id;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}public void setGender(String gender) {this.gender = gender;}public void setAddr(String addr) {this.addr = addr;}public Integer getId() {return id;}public String getUsername() {return username;}public String getPassword() {return password;}public String getGender() {return gender;}public String getAddr() {return addr;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", gender='" + gender + '\'' +", addr='" + addr + '\'' +'}';}
}
(2)加载核心配置文件,获取SqlSessionFactory对象
(3)获取SqlSession对象,执行SQL语句
(4)释放资源
/java/MyBatisDemo.java
import com.wmy.pojo.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;/*** MyBatis 快速入门代码*/
public class MyBatisDemo {public static void main(String[] args) throws IOException {//1.加载MyBatis的核心配置文件,获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2.获取SqlSession对象,用它来执行sqlSqlSession sqlSession = sqlSessionFactory.openSession();//3.执行sqlList<User> users = sqlSession.selectList("test.selectAll");System.out.println(users);//4.释放资源sqlSession.close();}
}

遇到的一些坑给大家说一下:
- 首先确定src文件下的java文件已经
Make Directory as为Sources Root,src文件下的resources文件已经Make Directory as为Resources Root。- 事前通过cmd管理员登录启动mysql服务,如何启动在最开始已经说过了,然后启动Navicat连接数据库之后,再考虑使用IDEA连接mysql数据库,可以通过mysql数据库的
Test Connection按钮尝试连接,这里比较容易报错,如果出现登录失败之类的问题,可以手动打开任务管理器,点击“详细信息”,关闭掉端口号为3306的服务(mysql数据库默认的端口号就是3306),然后重启mysql服务,需要注意的是,PID和端口号不是一回事,可以通过netstat -ano命令查询当前主机PID和端口号的对应关系,然后taskkill /pid掉端口号为3306的PID,即可使IDEA与mysql数据库连接成功,其实端口号为3306的进程就是“mysqld.exe”,它可能不止一个,kill掉它也就相当于重启mysql服务了,就不需要通过一系列命令查询PID与端口号的对应关系,亲测有效。IDEA连接好mysql数据库还有一个好处就是在pom.xml配置依赖dependency时,如果不知道你下载的mysql版本与mysql驱动版本的对应关系的话,当你打出来org.mybatis时,IDEA会自动生成适合你mysql版本的mysql驱动的版本。记得每次修改完pom.xml文件后reload一下。
- 关于maven项目的打包方式,如果是新手,建议在pom.xml文件中将packaging标签设置为jar打包方式,会生成与src同级的target目录,确保target文件中的classes目录下有mybatis-config.xml文件,没有的话可以尝试手动添加或者rebuild一下。
Mapper代理开发

如上图所示,MyBatis-Emo.java中存在硬编码的问题。
Mapper代理开发的目的在于:
- 解决原生方式中的硬编码。
- 简化后期执行SQL。
简言之,就是使用
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
来代替
List<User> users = sqlSession.selectList("test.selectAll");
这种方式有很多优势,首先它不依赖于字符串字面值,会更安全一点,其次,IDEA的代码补全功能可以快速选择到映射好的SQL语句。
需求
使用Mapper代理查询user表中的数据。
步骤
1.定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下。
方式一:不推荐直接将resources资源文件下的UserMapper.xml直接拖到java文件的mapper目录下,因为在Maven项目中要求java代码和xml文件要分开放,方便管理。
方式二:考虑到编译maven工程后会在target文件下生成一个classes目录,配置文件都会在classes目录下并且与类文件com同级,所以为了保证Mapper接口和SQL映射文件在编译之后在同一目录下,并且要求xml文件与java文件分开放置,我们可以在resources目录下建立一个与UserMapper.java一模一样的包结构,即如下所示。

maven项目编译后:

2.设置SQL映射文件的namespace属性为Mapper接口全限定名。
/resources/com.wmy.mapper/UserMapper.xml
<mapper namespace="com.wmy.mapper.UserMapper">
/resources/mybatis-config.xml
<mappers><!--指定当前sql文件映射路径--><!--在UserMapper.xml上鼠标右击 选择copy path-> Path From Source Root 然后把路径粘贴到mybatis-config.xml的mapper中的resource属性中--> <mapper resource="com/wmy/mapper/UserMapper.xml"/>
</mappers>
3.在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致。
/java/com.wmy.mapper/UserMapper.java
package com.wmy.mapper;
import com.wmy.pojo.User;
import java.util.List;
public interface UserMapper {//查询到的是一个集合 所以是List<User> 如果返回值是User 那么只会查找到一个对象List<User> selectAll();
}
4.编码
(1)通过SqlSession的getMapper方法获取Mapper接口的代理对象。
(2)调用对应方法完成sql的执行。
/java/com.wmy/MyBatisEmo.java
//3. 执行sql
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
System.out.println(users);
>注:需要在mysql数据库已经与IDEA连接的情况下运行代码。
有一点需要说的是,如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载。
/resources/mybatis-config.xml
<mappers><!--指定当前sql文件映射路径--><!--<mapper resource="com/wmy/mapper/UserMapper.xml"/>--><!--mapper代理的方式--><package name="com.wmy.mapper"/>
</mappers>
重新运行MyBatisEmo.java可以得到相同的查询结果,从上述xml代码中,我们可以看出,在java文件和resources文件中路径的命名方式是不同的(".“和”/"用来分级的区别),上述包扫描的方式是从java文件中扫描UserMapper.java文件的。
增删改查
环境准备
tb_brand.sql

/java/com.wmy.pojo/Brand.java
package com.wmy.pojo;
public class Brand {private Integer id;private String brandName;private String companyName;private Integer ordered;private String description;private Integer status;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getBrandName() {return brandName;}public void setBrandName(String brandName) {this.brandName = brandName;}public String getCompanyName() {return companyName;}public void setCompanyName(String companyName) {this.companyName = companyName;}public Integer getOrdered() {return ordered;}public void setOrdered(Integer ordered) {this.ordered = ordered;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';}
}
测试类

安装MyBatisX插件

安装后的效果:

该插件可以实现:
- XML和接口方法的相互跳转,比如说UserMapper.xml和UserMapper.java之间的快捷跳转。
- 根据接口方法生成statement,因为mapper接口要与sql映射文件中的方法名称相同,该插件可以保证名称不会起错。
配置文件完成增删改查
查询
(一)查询所有数据
步骤:
1.编写接口方法:mapper接口
- 参数:无
- 结果:List< Brand >
/java/com.wmy.mapper/BrandMapper.java
public interface BrandMapper {/** 查询所有* */public List<Brand> selectAll();
}
2.编写SQL语句:SQL映射文件
/resources/com.wmy.mapper/BrandMapper.xml
<mapper namespace="com.wmy.mapper.BrandMapper"><!--statement--><select id="selectAll" resultType="com.wmy.pojo.Brand">select *from tb_brand;</select>
</mapper>
3.执行方法,测试
/test/java/com.wmy.test/MyBatisTest.java
public class MyBatisTest {@Testpublic void testSelectAll() throws IOException {//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法List<Brand> brands = brandMapper.selectAll();System.out.println(brands);//5. 释放资源sqlSession.close();}
}

通过上述运行结果我们可以看出,数据库字表的字段名称和实体类的属性名称不一样,则不能自动封装数据。
方式一:起别名
/resources/com.wmy.mapper/BrandMapper.xml
<select id="selectAll" resultType="com.wmy.pojo.Brand">select id,brand_name as brandName,company_name as companyName,ordered, description, statusfrom tb_brand;
</select>
缺点在于每次查询都要定义一次别名,这里可以使用sql片段:
<sql id="brand_column">id,brand_name as brandName,company_name as companyName,ordered, description, status
</sql>
<!--statement-->
<select id="selectAll" resultType="com.wmy.pojo.Brand">select<include refid="brand_column"/>from tb_brand;
</select>
但是sql片段也存在缺点,就是它太不灵活了,假如我们不是查询全部数据呢,就需要重写sql片段。
方法二:使用resultMap
<resultMap id="brandResultMap" type="com.wmy.pojo.Brand"><result column="brand_name" property="brandName"></result><result column="company_name" property="companyName"></result>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">select *from tb_brand;
</select>
resultMap的使用方式

(二)查看详情
需求
点击查看详情,展示商品品牌信息
步骤
1.编写接口方法:Mapper接口
- 参数:id(int)
- 结果:Brand
/java/com.wmy.mapper/BrandMapper.java
Brand selectById(int id);
2.编写SQL语句:SQL映射文件
/resources/com.wmy.mapper/BrandMapper.xml
<!--参数占位符:1.#{}:会将其替换为? 防止SQL注入2.${}:拼sql 会存在SQL注入问题3.使用时机:参数传递的时候用:#{}表名或者列名不固定的情况下用:${}参数类型:parameterType属性 可以省略不写特殊字符处理:(如小于号<在xml文件中不能直接使用)1.转义字符2.CDATA区 :CD提示--><select id="selectById" resultMap="brandResultMap">select *from tb_brand where id = #{id};</select>
3.执行方法,测试
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testSelectById() throws IOException {int id = 1;//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法Brand brand = brandMapper.selectById(id);System.out.println(brand);//5. 释放资源sqlSession.close();
}
(三)条件查询
(1)多条件查询
需求
根据“当前状态”、“企业名称”和“品牌名称”三个选项进行多条件查询数据信息。
步骤
1.编写接口方法:Mapper接口
- 参数:所有查询条件
- 结果:List< Brand >
/java/com.wmy.mapper/BrandMapper.java
/** 条件查询* 参数接收* 1. 散装参数: 如果方法中有多个参数需要使用@Param("SQL参数占位符名称")* 2. 对象参数: 对象的属性名称要和SQL参数占位符名称一致* 3. map集合的参数: map集合的键的名称要和SQL参数占位符对应
* */
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);
2.编写SQL语句:SQL映射文件
/resources/com.wmy.mapper/BrandMapper.xml
<select id="selectByCondition" resultMap="brandResultMap">select *from tb_brandwhere status = #{status}and company_name like #{companyName}and brand_name like #{brandName};
</select>
3.执行方法,测试
重点:MyBatis如何接收多个参数 / 接口方法中参数的封装方式
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testSelectByCondition() throws IOException {// 接收参数int status = 1;String companyName = "华为";String brandName = "华为";// 处理参数companyName = "%" + companyName + "%";brandName = "%" + brandName + "%";// 封装参数/*Brand brand = new Brand();brand.setStatus(status);brand.setCompanyName(companyName);brand.setBrandName(brandName);*/Map map = new HashMap();map.put("status" , status);map.put("companyName" , companyName);map.put("brandName" , brandName);//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法//List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);//List<Brand> brands = brandMapper.selectByCondition(brand);List<Brand> brands = brandMapper.selectByCondition(map);System.out.println(brands);//5. 释放资源sqlSession.close();
}
(2)动态条件查询
SQL语句会随着用户的输入或外部条件的变化而变化,称为动态SQL。
1)多条件 - 动态查询
需求
在多条件查询的基础上,我们考虑这样一个问题,用户在输入条件时,是否所有条件都会填写?
方案:MyBatis逻辑标签的使用
/resources/com.wmy.mapper/BrandMapper.xml
①< if >判断标签 + 恒等式 让所有条件格式一致
<select id="selectByCondition" resultMap="brandResultMap">select *from tb_brandwhere 1=1<if test="status != null">and status = #{status}</if><if test="companyName != null and companyName != '' ">and company_name like #{companyName}</if><if test="brandName != null and brandName != '' ">and brand_name like #{brandName};</if>
</select>
②< where >标签替换 where关键字
<select id="selectByCondition" resultMap="brandResultMap">select *from tb_brand<where><if test="status != null">and status = #{status}</if><if test="companyName != null and companyName != '' ">and company_name like #{companyName}</if><if test="brandName != null and brandName != '' ">and brand_name like #{brandName};</if></where>
</select>
2)单条件 - 动态查询
需求
从多个条件中选择一个条件作为后续输入的限制。
/resources/com.wmy.mapper/BrandMapper.xml
<!--单条件- 动态查询 -->
<select id="selectByConditionSingle" resultMap="brandResultMap">select *from tb_brandwhere/*choose相当于switch when相当于case*/<choose><when test="status != null">status = #{status}</when><when test="companyName != null and companyName != '' ">company_name like #{companyName}</when><when test="brandName != null and brandName != '' ">brand_name like #{brandName}</when><otherwise>1=1</otherwise></choose>
</select>
<!--或者-->
<select id="selectByConditionSingle" resultMap="brandResultMap">select *from tb_brand<where><choose><when test="status != null">status = #{status}</when><when test="companyName != null and companyName != '' ">company_name like #{companyName}</when><when test="brandName != null and brandName != '' ">brand_name like #{brandName}</when></choose></where>
</select>
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testSelectByConditionSingle() throws IOException {// 接收参数int status = 1;String companyName = "华为";String brandName = "华为"; // 封装参数Brand brand = new Brand();brand.setStatus(status);brand.setCompanyName(companyName);brand.setBrandName(brandName);//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法List<Brand> brands = brandMapper.selectByConditionSingle(brand);System.out.println(brands);//5. 释放资源sqlSession.close();
}
添加
(一)简单添加
步骤
1.编写接口方法:Mapper接口
- 参数:除了id之外的所有数据
- 结果:void
/java/com.wmy.mapper/BrandMapper.java
void add(Brand brand);
2.编写SQL语句:SQL映射文件
/resources/com.wmy.mapper/BrandMapper.xml
<!--添加-->
<insert id="add">insert into tb_brand (brand_name ,company_name ,ordered ,description ,status)values (#{brandName} ,#{companyName} ,#{ordered} ,#{status});
</insert>
3.执行方法,测试
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testAdd() throws IOException {// 接收参数int status = 1;String companyName = "iPhone";String brandName = "苹果";String description = "加油苹果!加油额卖力卡!";int ordered = 100;// 封装参数Brand brand = new Brand();brand.setStatus(status);brand.setCompanyName(companyName);brand.setBrandName(brandName);brand.setDescription(description);brand.setOrdered(ordered);//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象(已经设置为自动提交事务到数据库)SqlSession sqlSession = sqlSessionFactory.openSession(true);//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法brandMapper.add(brand);//5. 释放资源sqlSession.close();
}
注:MyBatis事务
openSession():默认开启事务,进行增删改查操作后需要使用sqlSession.commit();手动提交事务
openSession(true):可以设置为自动提交事务(关闭事务)
(二)添加—主键返回
需求
在数据添加成功后,需要获取插入数据库数据的主键的值,比如说:添加订单和订单项。
1.添加订单
2.添加订单项,订单项中需要设置所属订单的id。
步骤
id作为商品的主键,在add()时并没有输入,需要获取id值,但是不能直接通过getId()方法获取。
只需要在简单添加的基础上,在**/resources/com.wmy.mapper/BrandMapper.xml**文件中的< insert >标签中,将useGeneratedKeys设置为true,将keyProperty属性设置为id即可。
修改
(一)修改全部字段
步骤
1.编写接口方法:Mapper接口
- 参数:所有数据
- 结果:int(影响的行数)
/java/com.wmy.mapper/BrandMapper.java
int update(Brand brand);
2.编写SQL语句:SQL映射文件
/resources/com.wmy.mapper/BrandMapper.xml
<!--修改-->
<update id="update">update tb_brandset brand_name = #{brandName},company_name = #{companyName},ordered = #{ordered},description = #{description},status = #{status}where id = #{id};
</update>
3.执行方法,测试
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testUpdate() throws IOException {// 接收参数int id = 5;int status = 1;String companyName = "苹果";String brandName = "iPhone";String description = "加油苹果!加油额卖力卡!";int ordered = 200;// 封装参数Brand brand = new Brand();brand.setStatus(status);brand.setCompanyName(companyName);brand.setBrandName(brandName);brand.setDescription(description);brand.setOrdered(ordered);brand.setId(id);//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession(true);//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法int rows = brandMapper.update(brand);System.out.println(rows);//5. 释放资源sqlSession.close();
}
(二)修改动态字段
需求
上述修改过程必须修改所有字段,不具有通用性。
/resources/com.wmy.mapper/BrandMapper.xml
<!--修改-->
<update id="update">update tb_brand<set><if test="brandName != null and brandName != ''">brand_name = #{brandName},</if><if test="companyName != null and companyName != ''">company_name = #{companyName},</if><if test="ordered != null">ordered = #{ordered},</if><if test="decription != null">description = #{description},</if><if test="status != null">status = #{status}</if></set>where id = #{id};
</update>
注:< set >标签可以解决空值输入时SQL语句的结束标志","的问题,并且不会出现只修改某个属性其他属性变为null的情况。
删除
(一)删除一个
/java/com.wmy.mapper/BrandMapper.java
void deleteById(int id);
/resources/com.wmy.mapper/BrandMapper.xml
<!--删除-->
<delete id="deleteById">deletefrom tb_brandwhere id = #{id};
</delete>
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testDeleteById() throws IOException {// 接收参数int id = 4;//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession(true);//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法brandMapper.deleteById(id);//5. 释放资源sqlSession.close();
}
(二)批量删除
/java/com.wmy.mapper/BrandMapper.java
void deleteByIds(@Param("ids")int[] ids);
/resources/com.wmy.mapper/BrandMapper.xml
<!--mybatis会将数组参数封装为一个Map集合方式一:默认键的集合叫做array 可以通过@param注解修改名称方式二:使用@Param注解改变Map集合默认key的名称
-->
<delete id="deleteByIds">delete from tb_brand where idin<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach>;
</delete>
/test/java/com.wmy.test/MyBatisTest.java
@Test
public void testDeleteByIds() throws IOException {// 接收参数int[] ids = {4,5,6};//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession(true);//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法brandMapper.deleteByIds(ids);//5. 释放资源sqlSession.close();
}
参数传递
MyBatis接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式。
1.单个参数
- POJO类型:可以直接使用,但是 属性名 要和 参数占位符名称 一致
- Map集合:可以直接使用,但是 键名 要和 参数占位符名称 一致
- Collection:封装为Map集合
map.put("arg0" ,collection集合);
map.put("collection", collection集合);
- List:封装为Map集合
map.put("arg0" ,list集合);
map.put("collection", list集合);
map.put("list" ,list集合);
- Array:封装为Map集合
map.put("arg0" , 数组);
map.put("array", 数组);
- 其他类型:可以直接使用
2.多个参数:MyBatis会将其封装为Map集合
比如说有一个Mapper映射接口中传入了username和password两个参数。
那么这两个参数会被getParamName()方法自动封装为map集合,具体键值对的构造就相当于:
map.put("arg0", username);
map.put("param1", username);
map.put("param2", password);
map.put("arg1", password);
但是这种自动封装的方式阅读性太差了,所以这里可以使用@Param注解替换Map集合中默认的键名。
//username和password被封装为map对象后,对应的键名为param1和param2 或者是arg0和arg1
User select(String username , String password);
//此时使用Param注解后 username和password对应的键名为username和password
User select(@Param("username")String username ,@Param("password")String password);
总之,无论是单个参数还是多个参数被封装为Map对象,将来都建议使用@Param注解来修改Map集合中默认的键名,并使用修改后的名称来获取值,这样可读性更高。
注解完成增删改查
用官方的话来说,使用注解未映射简单语句会使代码显得更加苒洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让你本就复杂的SQL语句更加最乱不堪。因此,如果你需要做一些很复杂的捐作,最好用XML来映射语句。
选择何种方式来配置映射,以及认为是否应该要统─缺射话句定义的形式,完全取决于你和次的团队。换句话说,永远不要拘于一种方式。你可以很轻松的在基于注解和XML的句映射方式间自由移植和切换。
- 查询:
@Select - 添加:
@Insert - 修改:
@Update - 删除:
@Delete
例如:
/java/com.wmy.mapper/UserMapper.java
@Select("select * from tb_user where id = #{id}")
User selectById(int id);
相关文章:
MyBatis的基本使用及常见问题
MyBatis 前言MyBatis简介MyBatis快速上手Mapper代理开发增删改查环境准备配置文件完成增删改查查询添加修改删除 参数传递注解完成增删改查 前言 JavaWeb JavaWeb是用Java技术来解决相关Web互联网领域的技术栈。 MySQL数据库与SQL语言 MySQL:开源的中小型数据库。…...
[RoarCTF2019] TankGame
不多说,用dnspy反编译data文件夹中的Assembly-CSharp文件 使用分析器分析一下可疑的FlagText 发现其在WinGame中被调用,跟进WinGame函数 public static void WinGame(){if (!MapManager.winGame && (MapManager.nDestroyNum 4 || MapManager.n…...
相比于其他流处理技术,Flink的优点在哪?
Apache Flink 是一个开源的流处理框架,用于在高吞吐量和低延迟的情况下进行大规模数据流的处理。Flink 以其在流处理领域的性能而闻名,相比于其他流处理技术,Flink 提供了一些独特的特性和优化,使其在某些情况下更快。以下是 Flin…...
react中使用ref属性获取元素,并判断该元素内是否含有子元素
在react中,可以使用ref属性来获取到一个元素的引用,然后再使用ref.current来访问该元素的DOM节点,使用DOM API来判断这个元素是否含有子元素,要判断一个元素是否含有子元素,可以使用hasChildNodes(),其返回…...
idea 如何快速拉取新分支
方式1 (快捷键:CtrlShift~) 方式2:(快捷键:Alt9)...
【经验分享】日常开发中的故障排查经验分享(一)
目录 简介CPU飙高问题1、使用JVM命令排查CPU飙升100%问题2、使用Arthas的方式定位CPU飙升问题3、Java项目导致CPU飙升的原因有哪些?如何解决? OOM问题(内存溢出)1、如何定位OOM问题?2、OOM问题产生原因 死锁问题的定位…...
关于Unity使用图片字体示例
1.使用TexturePacker打包图集 下载地址 TexturePacker - Create Sprite Sheets for your game! 2.准备好数字图 3. 导入图片 4. 打包图集需要的设置 将重心点设置为左下方 点击回车 > 后点击回 >到精灵列表 选择导出的格式 导出后的内容 >导入unity 导入 >…...
开源大语言模型简记
文章目录 开源大模型LlamaChinese-LLaMA-AlpacaLlama2-ChineseLinlyYaYiChatGLMtransformersGPT-3(未完全开源)BERTT5QwenBELLEMossBaichuan其他...
python高级代码
目录 列表推导式和生成器表达式:使用简洁的语法来生成列表和生成器。 装饰器:用于修改函数行为的函数。 上下文管理器:用于管理资源的对象,可以使用with语句来自动管理资源的分配和释放。 多线程和多进程编程:使用…...
透彻掌握GIT基础使用
网址 https://learngitbranching.js.org/?localezh_CN 清屏 clear重新开始reset...
二、类与对象(三)
17 初始化列表 17.1 初始化列表的引入 之前我们给成员进行初始化时,采用的是下面的这种方式: class Date { public:Date(int year, int month, int day)//构造函数{_year year;_month month;_day day;} private:int _year;int _month;int _day; };…...
CentOS 7 Tomcat服务的安装
前提 安装java https://blog.csdn.net/qq_36940806/article/details/134945175?spm1001.2014.3001.5501 1. 下载 wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.84/bin/apache-tomcat-9.0.84.tar.gzps: 可选择自己需要的版本下载安装https://mir…...
文件夹共享功能的配置 以及Windows server2012防火墙的配置
目录 一. 配置文件夹共享功能 1.1 为什么需要配置文件夹共享功能 1.2 配置文件夹共享 1.3 访问共享文件夹 1.4 配置取消 用户名和密码认证 二. windows server 2012防火墙配置 思维导图 一. 配置文件夹共享功能 1.1 为什么需要配置文件夹共享功能 我们在工作和生活中经…...
前端使用高德api的AMap.Autocomplete无效,使用AMap.Autocomplete报错
今天需要一个坐标拾取器,需要一个输入框输入模糊地址能筛选的功能 查看官方文档,有一个api可以直接满足我们的需求 AMap.Autocomplete 上代码 AMapLoader.load({"key": "你的key", // 申请好的Web端开发者Key,首次调…...
反转链表、链表的中间结点、合并两个有序链表(leetcode 一题多解)
一、反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 思路一:翻转单链表指针方向 这里解释一下三个指针的作用: n1࿱…...
深度学习中的Dropout
1 Dropout概述 1.1 什么是Dropout 在2012年,Hinton在其论文《Improving neural networks by preventing co-adaptation of feature detectors》中提出Dropout。当一个复杂的前馈神经网络被训练在小的数据集时,容易造成过拟合。为了防止过拟合ÿ…...
MySQL 中的 ibdata1 文件过大如何处理?
ibdata1 是什么文件? ibdata1 是InnoDB的共有表空间,默认情况下会把表空间存放在一个名叫 ibdata1的文件中,日积月累会使该文件越来越大。 ibdata1 文件过大的解决办法 使用独享表空间,将表空间分别单独存放。MySQL开启独享表空…...
Weblogic反序列化远程命令执行(CVE-2019-2725)
漏洞描述: CVE-2019-2725是一个Oracle weblogic反序列化远程命令执行漏洞,这个漏洞依旧是根据weblogic的xmldecoder反序列化漏洞,通过针对Oracle官网历年来的补丁构造payload来绕过。 复现过程: 1.访问ip:port 2.可…...
鸿蒙组件数据传递:ui传递、@prop、@link
鸿蒙组件数据传递方式有很多种,下面详细罗列一下: 注意: 文章内名词解释: 正向:父变子也变 逆向:子变父也变 **第一种:直接传递 - 特点:1、任何数据类型都可以传递 2、不能响应式…...
ubuntu 开机自报IP地址(用于无屏幕小车-远程连接)
目录 1.环境安装2.代码3.打包成可执行文件4.开启开机自启 1.环境安装 sudo apt-get install espeak #先安装这个库 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyttsx32.90 #再安装pyttsx3 pyinstaller pip install -i https://pypi.tuna.tsinghua.edu.cn/si…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
Python网页自动化Selenium中文文档
1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API,让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API,你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
AT模式下的全局锁冲突如何解决?
一、全局锁冲突解决方案 1. 业务层重试机制(推荐方案) Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减(自动加全…...



>注:需要在mysql数据库已经与IDEA连接的情况下运行代码。