二、MyBatis 基本使用

本章概要

  • 向SQL语句传参
  • 数据输入
    • Mybatis总体机制概括
    • 概念说明
    • 单个简单类型参数
    • 实体类类型参数
    • 零散的简单类型数据
    • Map类型参数
  • 数据输出
    • 输出概述
    • 单个简单类型
    • 返回实体类对象
    • 返回Map类型
    • 返回List类型
    • 返回主键值
    • 实体类属性和数据库字段对应关系
  • CRUD强化练习
  • mapperXML标签总结

2.1 向 SQL 语句传参

2.1.1 mybatis 日志输出配置

mybatis配置文件设计标签和顶层结构如下:

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

可以在mybatis的配置文件使用settings标签设置,输出运过程SQL日志!通过查看日志,可以判定 #{} 和 ${} 的输出效果!

settings设置项:

logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J(3.5.9 起废弃) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置

日志配置:

<settings><!-- SLF4J 选择slf4j输出! --><setting name="logImpl" value="SLF4J"/>
</settings>

2.1.2 #{}形式

Mybatis 会将 SQL 语句中的 #{} 转换为问号占位符。

在这里插入图片描述

2.1.3 ${}形式

${} 形式传参,底层 Mybatis 做的是字符串拼接操作。

在这里插入图片描述

通常不会采用 ${} 的方式传值。一个特定的适用场景是:通过 Java 程序动态生成数据库表,表名部分需要 Java 程序通过参数传入;而JDBC对于表名部分是不能使用问号占位符的,此时只能使用

结论:实际开发中,能用 #{} 实现的,肯定不用 ${}。

特殊情况: 动态的不是值,是列名或者关键字,需要使用 ${} 拼接

//注解方式传入参数!!
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

2.2 数据输入

2.2.1 Mybatis总体机制概括

在这里插入图片描述

2.2.2 概念说明

这里数据输入具体是指上层方法(例如Service方法)调用Mapper接口时,数据传入的形式。

  • 简单类型:只包含一个值的数据类型
    • 基本数据类型:int、byte、short、double、……
    • 基本数据类型的包装类型:Integer、Character、Double、……
    • 字符串类型:String
  • 复杂类型:包含多个值的数据类型
    • 实体类类型:Employee、Department、……
    • 集合类型:List、Set、Map、……
    • 数组类型:int[]、String[]、……
    • 复合类型:List、实体类中包含集合……

2.2.3 单个简单类型参数

Mapper接口中抽象方法的声明

Employee selectEmployee(Integer empId);

SQL语句

<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
</select>

单个简单类型参数,在 #{} 中可以随意命名,但是没有必要。通常还是使用和接口方法参数同名。

2.2.4 实体类类型参数

Mapper 接口中抽象方法的声明

int insertEmployee(Employee employee);

SQL 语句

<insert id="insertEmployee">insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>

对应关系

在这里插入图片描述

结论:
Mybatis会根据#{}中传入的数据,加工成getXxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}解析后的问号占位符这个位置。

2.2.5 零散的简单类型数据

零散的多个简单类型参数,如果没有特殊处理,那么Mybatis无法识别自定义名称:

在这里插入图片描述

Mapper接口中抽象方法的声明

int updateEmployee(@Param("empId") Integer empId,@Param("empSalary") Double empSalary);

SQL语句

<update id="updateEmployee">update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
</update>

对应关系

在这里插入图片描述

2.2.6 Map类型参数

Mapper接口中抽象方法的声明

int updateEmployeeByMap(Map<String, Object> paramMap);

SQL语句

<update id="updateEmployeeByMap">update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey}</update>

junit测试

private SqlSession session;
//junit5会在每一个@Test方法前执行@BeforeEach方法
@BeforeEach
public void init() throws IOException {
session = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-config.xml"))
.openSession();
}@Test
public void testUpdateEmpNameByMap() {EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);Map<String, Object> paramMap = new HashMap<>();paramMap.put("empSalaryKey", 999.99);paramMap.put("empIdKey", 5);int result = mapper.updateEmployeeByMap(paramMap);log.info("result = " + result);
}//junit5会在每一个@Test方法后执行@@AfterEach方法
@AfterEach
public void clear() {session.commit();session.close();
}

对应关系

  • #{}中写Map中的key

使用场景

  • 有很多零散的参数需要传递,但是没有对应的实体类类型可以使用。使用@Param注解一个一个传入又太麻烦了。所以都封装到Map中。

2.3 数据输出

2.3.1 输出概述

数据输出总体上有两种形式:

  • 增删改操作返回的受影响行数:直接使用 int 或 long 类型接收即可
  • 查询操作的查询结果

我们需要做的是,指定查询的输出数据类型即可!
并且插入场景下,实现主键数据回显示!

2.3.2 单个简单类型

Mapper接口中的抽象方法

int selectEmpCount();

SQL语句

<select id="selectEmpCount" resultType="int">select count(*) from t_emp
</select>

Mybatis 内部给常用的数据类型设定了很多别名。 以 int 类型为例,可以写的名称有:int、integer、Integer、java.lang.Integer、Int、INT、INTEGER 等等。

junit测试

@Testpublic void testEmpCount() {EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);int count = employeeMapper.selectEmpCount();log.info("count = " + count);}

细节解释:

  • select标签,通过resultType指定查询返回值类型!
  • resultType = “全限定符 | 别名 | 如果是返回集合类型,写范型类型即可”

别名问题:

https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases><typeAlias alias="Author" type="domain.blog.Author"/><typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>

当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

<typeAliases> <package name="domain.blog"/> </typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:

@Alias("author")
public class Author {...
}

下面是Mybatis为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_char (since 3.5.10)char
_character (since 3.5.10)char
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
char (since 3.5.10)Character
character (since 3.5.10)Character
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
bigintegerBigInteger
objectObject
object[]Object[]
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection

2.3.3 返回实体类对象

Mapper 接口的抽象方法

Employee selectEmployee(Integer empId);

SQL语句

<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 -->
<!-- resultType属性:指定封装查询结果的Java实体类的全类名 -->
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee"><!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符 --><!-- 给每一个字段设置一个别名,让别名和Java实体类中属性名一致 -->select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}</select>

通过给数据库表字段加别名,让查询结果的每一列都和Java实体类中属性对应起来。

增加全局配置自动识别对应关系

在 Mybatis 全局配置文件中,做了下面的配置,select语句中可以不给字段设置别名

<!-- 在全局范围内对Mybatis进行配置 -->
<settings><!-- 具体配置 --><!-- 从org.apache.ibatis.session.Configuration类中可以查看能使用的配置项 --><!-- 将mapUnderscoreToCamelCase属性配置为true,表示开启自动映射驼峰式命名规则 --><!-- 规则要求数据库表字段命名方式:单词_单词 --><!-- 规则要求Java实体类属性名命名方式:首字母小写的驼峰式命名 --><setting name="mapUnderscoreToCamelCase" value="true"/></settings>

2.3.4 返回Map类型

适用于SQL查询返回的各个字段综合起来并不和任何一个现有的实体类对应,没法封装到实体类对象中。能够封装成实体类类型的,就不使用Map类型。

Mapper接口的抽象方法

Map<String,Object> selectEmpNameAndMaxSalary();

SQL语句

<!-- Map<String,Object> selectEmpNameAndMaxSalary(); -->
<!-- 返回工资最高的员工的姓名和他的工资 -->
<select id="selectEmpNameAndMaxSalary" resultType="map">SELECTemp_name 员工姓名,emp_salary 员工工资,(SELECT AVG(emp_salary) FROM t_emp) 部门平均工资FROM t_emp WHERE emp_salary=(SELECT MAX(emp_salary) FROM t_emp)
</select>

junit测试

@Test
public void testQueryEmpNameAndSalary() {EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);Map<String, Object> resultMap = employeeMapper.selectEmpNameAndMaxSalary();Set<Map.Entry<String, Object>> entrySet = resultMap.entrySet();for (Map.Entry<String, Object> entry : entrySet) {String key = entry.getKey();Object value = entry.getValue();log.info(key + "=" + value);}
}

2.3.5 返回List类型

查询结果返回多个实体类对象,希望把多个实体类对象放在List集合中返回。此时不需要任何特殊处理,在resultType属性中还是设置实体类类型即可。

Mapper接口中抽象方法

List<Employee> selectAll();

SQL语句

<!-- List<Employee> selectAll(); -->
<select id="selectAll" resultType="com.atguigu.mybatis.entity.Employee">select emp_id empId,emp_name empName,emp_salary empSalaryfrom t_emp
</select>

junit测试

@Test
public void testSelectAll() {EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);List<Employee> employeeList = employeeMapper.selectAll();for (Employee employee : employeeList) {log.info("employee = " + employee);}
}

2.3.6 返回主键值

  1. 自增长类型主键

Mapper接口中的抽象方法

int insertEmployee(Employee employee);

SQL语句

<!-- int insertEmployee(Employee employee); -->
<!-- useGeneratedKeys属性字面意思就是“使用生成的主键” -->
<!-- keyProperty属性可以指定主键在实体类对象中对应的属性名,Mybatis会将拿到的主键值存入这个属性 -->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="empId">insert into t_emp(emp_name,emp_salary)values(#{empName},#{empSalary})
</insert>

junit测试

@Test
public void testSaveEmp() {EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);Employee employee = new Employee();employee.setEmpName("john");employee.setEmpSalary(666.66);employeeMapper.insertEmployee(employee);log.info("employee.getEmpId() = " + employee.getEmpId());
}

注意:
Mybatis 是将自增主键的值设置到实体类对象中,而不是以Mapper接口方法返回值的形式返回。

  1. 非自增长类型主键

而对于不支持自增型主键的数据库(例如 Oracle)或者字符串类型主键,则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用!

使用 selectKey 帮助插入UUID作为字符串类型主键示例:

<insert id="insertUser" parameterType="User"><selectKey keyProperty="id" resultType="java.lang.String"order="BEFORE">SELECT UUID() as id</selectKey>INSERT INTO user (id, username, password) VALUES (#{id},#{username},#{password})
</insert>

在上例中,我们定义了一个 insertUser 的插入语句来将 User 对象插入到 user 表中。我们使用 selectKey 来查询 UUID 并设置到 id 字段中。通过 keyProperty 属性来指定查询到的 UUID 赋值给对象中的 id 属性,而 resultType 属性指定了 UUID 的类型为 java.lang.String。

需要注意的是,我们将 selectKey 放在了插入语句的前面,这是因为 MySQL 在 insert 语句中只支持一个 select 子句,而 selectKey 中查询 UUID 的语句就是一个 select 子句,因此我们需要将其放在前面。

最后,在将 User 对象插入到 user 表中时,我们直接使用对象中的 id 属性来插入主键值。使用这种方式,我们可以方便地插入 UUID 作为字符串类型主键。当然,还有其他插入方式可以使用,如使用Java代码生成UUID并在类中显式设置值等。需要根据具体应用场景和需求选择合适的插入方式。

2.3.7 实体类属性和数据库字段对应关系

  1. 别名对应

将字段的别名设置成和实体类属性一致。

<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 -->
<!-- resultType属性:指定封装查询结果的Java实体类的全类名 -->
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee"><!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符 --><!-- 给每一个字段设置一个别名,让别名和Java实体类中属性名一致 -->select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}</select>

关于实体类属性的约定:getXxx()方法、setXxx()方法把方法名中的get或set去掉,首字母小写。

  1. 全局配置自动识别驼峰式命名规则

在Mybatis全局配置文件加入如下配置:

<!-- 使用settings对Mybatis全局进行设置 -->
<settings><!-- 将xxx_xxx这样的列名自动映射到xxXxx这样驼峰式命名的属性名 --><setting name="mapUnderscoreToCamelCase" value="true"/></settings>

SQL语句中可以不使用别名

<!-- Employee selectEmployee(Integer empId); -->
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}</select>
  1. 使用resultMap

使用resultMap标签定义对应关系,再在后面的SQL语句中引用这个对应关系

<!-- 专门声明一个resultMap设定column到property之间的对应关系 -->
<resultMap id="selectEmployeeByRMResultMap" type="com.atguigu.mybatis.entity.Employee"><!-- 使用id标签设置主键列和主键属性之间的对应关系 --><!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 --><id column="emp_id" property="empId"/><!-- 使用result标签设置普通字段和Java实体类属性之间的关系 --><result column="emp_name" property="empName"/><result column="emp_salary" property="empSalary"/></resultMap><!-- Employee selectEmployeeByRM(Integer empId); -->
<select id="selectEmployeeByRM" resultMap="selectEmployeeByRMResultMap">select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}</select>

2.4 CRUD强化练习

  1. 准备数据库数据

首先,需要准备一张名为 user 的表。该表包含字段 id(主键)、username、password。创建SQL如下:

CREATE TABLE `user` (`id` INT(11) NOT NULL AUTO_INCREMENT,`username` VARCHAR(50) NOT NULL,`password` VARCHAR(50) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 实体类准备

接下来,需要定义一个实体类 User,来对应 user 表的一行数据。

@Data //lombok
public class User {private Integer id;private String username;private String password;@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}

lombok pom 依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>compile</scope>
</dependency>
  1. Mapper接口定义

定义一个 Mapper 接口 UserMapper,并在其中添加 user 表的增、删、改、查方法。

public interface UserMapper {int insert(User user);int update(User user);int delete(Integer id);User selectById(Integer id);List<User> selectAll();
}
  1. MapperXML编写

在 resources/mappers目录下创建一个名为 UserMapper.xml 的 XML 文件,包含与 Mapper 接口中相同的五个 SQL 语句,并在其中,将查询结果映射到 User 实体中。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.atguigu.mapper.UserMapper"><!-- 定义一个插入语句,并获取主键值 --><insert id="insert" useGeneratedKeys="true" keyProperty="id">INSERT INTO user(username, password)VALUES(#{username}, #{password})</insert><update id="update">UPDATE user SET username=#{username}, password=#{password}WHERE id=#{id}</update><delete id="delete">DELETE FROM user WHERE id=#{id}</delete><!-- resultType使用user别名,稍后需要配置!--><select id="selectById" resultType="user">SELECT id, username, password FROM user WHERE id=#{id}</select><!-- resultType返回值类型为集合,所以只写范型即可! --><select id="selectAll" resultType="user">SELECT id, username, password FROM user</select></mapper>
  1. 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><settings><!-- 开启驼峰式映射--><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 开启logback日志输出--><setting name="logImpl" value="SLF4J"/></settings><typeAliases><!-- 给实体类起别名 --><package name="com.atguigu.entity"/></typeAliases><!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 --><environments default="development"><!-- environment表示配置Mybatis的一个具体的环境 --><environment id="development"><!-- Mybatis的内置的事务管理器 --><transactionManager type="JDBC"/><!-- 配置数据源 --><dataSource type="POOLED"><!-- 建立数据库连接的具体信息 --><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><mappers><!-- Mapper注册:指定Mybatis映射文件的具体位置 --><!-- mapper标签:配置一个具体的Mapper映射文件 --><!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 --><!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 --><mapper resource="mappers/UserMapper.xml"/></mappers></configuration>
  1. 效果测试
package com.atguigu.test;import com.atguigu.entity.User;
import com.atguigu.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;import java.io.IOException;
import java.util.List;/*** projectName: com.atguigu.test*/
public class MyBatisTest {private SqlSession session;// junit会在每一个@Test方法前执行@BeforeEach方法@BeforeEachpublic void init() throws IOException {session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();}@Testpublic void testAll(){createTest();updateTest();selectByIdTest();selectAllTest();deleteTest();}@Testpublic void createTest() {User user = new User();user.setUsername("admin");user.setPassword("123456");UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.insert(user);System.out.println(user);}@Testpublic void updateTest() {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.selectById(1);user.setUsername("root");user.setPassword("111111");userMapper.update(user);user = userMapper.selectById(1);System.out.println(user);}@Testpublic void deleteTest() {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.delete(1);User user = userMapper.selectById(1);System.out.println("user = " + user);}@Testpublic void selectByIdTest() {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.selectById(1);System.out.println("user = " + user);}@Testpublic void selectAllTest() {UserMapper userMapper = session.getMapper(UserMapper.class);List<User> userList = userMapper.selectAll();System.out.println("userList = " + userList);}// junit会在每一个@Test方法后执行@@AfterEach方法@AfterEachpublic void clear() {session.commit();session.close();}
}

在这里插入图片描述

2.5 mapperXML标签总结

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

**select**标签:
MyBatis 在查询和结果映射做了相当多的改进。一个简单查询的 select 元素是非常简单:

<select id="selectPerson" resultType="hashmap" resultMap="自定义结构"> SELECT * FROM PERSON WHERE ID = #{id} 
</select>

这个语句名为 selectPerson,接受一个 int(或 Integer)类型的参数,并返回一个 HashMap 类型的对象,其中的键是列名,值便是结果行中的对应值。

注意参数符号:#{id} ${key}

MyBatis 创建一个预处理语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:

// 近似的 JDBC 代码,非 MyBatis 代码...
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

select 元素允许你配置很多属性来配置每条语句的行为细节:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。

**insert****, **update** 和 ****delete**标签

数据变更语句 insert,update 和 delete 的实现非常接近:

<insertid="insertAuthor"statementType="PREPARED"keyProperty=""keyColumn=""useGeneratedKeys=""timeout="20">...
</insert>
<updateid="updateAuthor"statementType="PREPARED"timeout="20">...
</update>
<deleteid="deleteAuthor"statementType="PREPARED"timeout="20">...
</delete>
属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/611538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea git回滚之前提交记录

提交代码时&#xff0c;如果不小心提交了不需要提交的内容&#xff0c;在本地仓库中&#xff0c;此时需要回滚版本&#xff0c;如何回滚 1.打开git控制台&#xff0c;左下角git,选择要处理的分支&#xff0c;选择刷新获取最新git提交记录 2&#xff09;选中自己commit需要回滚…

教你用SadTalker一键整合包轻松制作专属数字人

数字人的效果&#xff1a; &#x1f3b5;我用SadTalker制作了专属虚拟数字人&#xff0c;还会唱歌哦&#xff0c;多多点赞关注就出教程呦&#x1f497; SadTalker有独立离线版Ai数字人&#xff0c;也可以在Stable Diffusion以插件的形式使用&#xff0c;但是如果显卡小的话还是…

开始卷TED:第1篇 —— 《Embrace the near win》—— part: 3

She first hit a seven, I remember, and then a nine, and then two tens, and then the next arrow didn’t even hit the target. 她第一次射中了7环&#xff0c; 我记得接下来是个9环&#xff0c;然后是2个十环&#xff0c;接下来的那支箭甚至没有射到靶上。 And I saw tha…

强化学习10——免模型控制Q-learning算法

Q-learning算法 主要思路 由于 V π ( s ) ∑ a ∈ A π ( a ∣ s ) Q π ( s , a ) V_\pi(s)\sum_{a\in A}\pi(a\mid s)Q_\pi(s,a) Vπ​(s)∑a∈A​π(a∣s)Qπ​(s,a) &#xff0c;当我们直接预测动作价值函数&#xff0c;在决策中选择Q值最大即动作价值最大的动作&…

【Vue3】2-4 : 声明式渲染及响应式数据实现原理

本书目录&#xff1a;点击进入 一、声明式渲染 1.1 什么是JS表达式&#xff1a;能够进行赋值的操作 ▶ 正确 ▶ 错误示例 二、示例&#xff1a;2秒后&#xff0c;页面中 message 由 hello world 变成 hi vue ▶ 效果 三、原理&#xff1a;利用ES6的Proxy对象对底层进…

achievement_criteria_data

achievement_criteria_data&#xff08;335&#xff09; 此表用来确定获得成就所需条件 criteria_id &#xff1a;ID&#xff0c;取值参考 Achievement_Criteria.dbctype &#xff1a;这个字段决定 value1 和 value2 数据的作用&#xff0c;详细数据见下表ScriptName&#xf…

Linux网络编程(一-网络相关知识点)

目录 一、网络相关知识简介 二、网络协议的分层模型 2.1 OSI七层模型 2.2 TCP/IP五层模型 2.3 协议层报文间的封装与拆封 三、IP协议 3.1 MAC地址 3.2 IP地址 3.3 MAC地址与IP地址区别 一、网络相关知识简介 互联网通信的本质是数字通信&#xff0c;任何数字通信都离…

千问写作——论文写作

【千问写作】 千问写作是运用通义千问720亿参数的语言模型&#xff08;qwen-72b-chat&#xff09;进行基于目录的论文创作&#xff0c;通过python-docx设置文档格式然后写出文档 &#xff0c;其他免费模型&#xff08;qwen-1.8b-chat&#xff09;暂时无法生成目录 1. 请求延时 …

Docker实战10|实现volum数据卷

上一篇文章中&#xff0c;仔细讲解了Docker是如何改变当前的root文件系统以及mount等操作。 本文继续讲解Docker是如何实现Volum数据卷的。 实现Volume数据卷 获取代码 git clone https://gitee.com/mjreams/docker.git 上一小节介绍了如何使用AUFS包装busybox&#xff0c…

Windows11快速安装Android子系统

很多小伙伴想在电脑运行一下安卓程序&#xff0c;或则上班用手机摸鱼不方便&#xff0c;用电脑又没有想要的手机软件&#xff0c;那么怎么用电脑来安装安卓软件呢&#xff1f; 首先设置地区 安装Android子系统的前提需要安装 Amazon Appstore 这个应用&#xff0c;内地不能下载…

【博士每天一篇论文-算法】Optimal modularity and memory capacity of neural reservoirs

阅读时间&#xff1a;2023-11-15 1 介绍 年份&#xff1a;2019 作者&#xff1a;Nathaniel Rodriguez 印第安纳大学信息学、计算和工程学院&#xff0c;美国印第安纳州布卢明顿 期刊&#xff1a; Network Neuroscience 引用量&#xff1a;39 这篇论文主要研究了神经网络的模块…

SpringBoot+Redis实现接口防刷功能

场景描述&#xff1a; 在实际开发中&#xff0c;当前端请求后台时&#xff0c;如果后端处理比较慢&#xff0c;但是用户是不知情的&#xff0c;此时后端仍在处理&#xff0c;但是前端用户以为没点到&#xff0c;那么再次点击又发起请求&#xff0c;就会导致在短时间内有很多请求…

RK3568平台开发系列讲解(Linux系统篇)Linux 内核打印

🚀返回总目录 文章目录 一、方法一:dmseg 命令二、方法二:查看 kmsg 文件三、方法三:调整内核打印等级一、方法一:dmseg 命令 在终端使用 dmseg 命令可以获取内核打印信息,该命令的具体使用方法如下所示: 首先在串口终端使用 “dmseg”命令,可以看见相应的内核打印信息…

Java基础- 泛型

泛型是 Java 编程语言的一个特性&#xff0c;它允许在编写和使用类、接口和方法时添加类型参数。泛型的主要目的是提高代码的可重用性、类型安全性和可读性。 泛型方法允许在方法级别上指定类型参数&#xff0c;提供了极大的灵活性和类型安全性。以下是一个泛型方法的示例&…

Windows.OpenSSL生成ssl证书配置到nginx

一、下载OpenSSL程序安装 到E:\soft\OpenSSL-Win64 二、打开一个CMD控制台窗口&#xff0c;设置好openssl.cnf路径 E: cd E:\soft\OpenSSL-Win64\bin set OPENSSL_CONFE:\soft\OpenSSL-Win64\bin\openssl.cnf 三、在当前目录 E:\soft\OpenSSL-Win64\bin 里创建两个子目录 m…

力扣103. 二叉树的锯齿形层序遍历

广度优先搜索 思路&#xff1a; 需要逐层遍历结果&#xff0c;通过广度优先搜索即可&#xff1b; 使用 queue&#xff0c;初始将 root push 进入 queue&#xff1b;逐层搜索&#xff0c;直到 queue 为空&#xff1b; queue 里为当前层节点元素&#xff0c;一次循环处理&#x…

酿酒生产废水处理设备如何选型

选型酿酒生产废水处理设备是确保废水处理过程高效稳定的关键步骤。酿酒生产过程中&#xff0c;产生的废水中含有大量有机物和悬浮物&#xff0c;因此需要选择适合的设备来进行处理。 首先&#xff0c;要根据酿酒生产废水的特点进行选型。酿酒废水的主要特点是&#xff1a;水量较…

uni-app使用uni-ui加ts类型限制

uni-app使用uni-ui加ts类型限制 安装 uni-ui 组件库 pnpm i dcloudio/uni-ui配置自动导入组件 // pages.json {// 组件自动导入"easycom": {"autoscan": true,"custom": {// uni-ui 规则如下配置 "^uni-(.*)": "dcloudio/uni…

phpstorm配置ftp

1 选择设置ftp 2设置自动上传

分享两个概念:非受检异常和受检异常

分享两个概念&#xff1a;非受检异常和受检异常 愿你的每一天都充满阳光和笑声&#xff0c;愿每一步都是轻松与愉快。在新的旅程中&#xff0c;愿你找到勇气攀登高峰&#xff0c;找到智慧化解困境。 愿你的心中充满温暖和善意&#xff0c;愿你的梦想如彩虹般美丽且真实。愿你发…