学习之前:
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
2.1 向SQL语句传参
2.1.1 mybatis日志输出配置
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">
<configuration>
<!-- 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="hutao"/>
<property name="password" value="lld666666"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
<!-- mapper标签:配置一个具体的Mapper映射文件 -->
<!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
<!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
<mapper resource="mappers/EmployeeMapper.xml"/>
</mappers>
</configuration>
<environments>标签:
用于选择MyBatis配置环境的标签,如开发、测试和生产环境需要不同的配置。更换环境,只需更开<environments>标签中的default属性值即可。如上述XML文件中的配置说明当前使用的是开发环境。<environment>标签则配置了不同环境需要的配置信息。
<transcationManager>标签:
MyBatis中有两种事务管理器:type = "JDBC" / "MANAGED"
JDBC:直接使用JDBC的提交和回滚功能。(常用)
MANAGED:不提交或回滚一个连接(基本什么都不做),需要自己提交。
<datasource>标签:
配置数据源,使用JDBC数据源接口来配置JDBC连接对象的资源。
UNPOOLED:每次请求时打开和关闭连接。
POOLED:利用“池”的概念讲JDBC连接对象组织起来。(常用)
<mappers>标签:
定义SQL映射语句,告诉MyBatis去哪里找到这些语句。
<mapper class="com.xx.yy.ZzzMapper"> 使用类的全限定符来定位Mapper映射文件。
如何打开日志?
按照配置文件的顺序,声明<settings>标签。<settings>标签内声明<setting>标签,name="logImpl",value="STDOUT_LOGGING"。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2.1.2 传参的两种形式
#{key} 形式
以?占位符的形式动态传参
${key}形式
以字符串拼接的形式传参
推荐使用#{key} 形式传参:
防止注入攻击。但是#{key}形式不能动态传入标签、列名、SQL关键字
故动态传入列名或表名时,可以用${key}形式传入
<mapper namespace="com.landy.mapper.EmployeeMapper">
<!--
两种传参符号:
#{ key }:占位符+赋值 id = ? ? = 赋值
${ key }:拼接字符串 "id = " + id
推荐使用#{}:防止注入攻击的问题,不能替代容器名(标签、列明、SQL关键字)
若列名或表名是动态传入的,则需要${}
-->
<select id="queryById" resultType="com.landy.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary from t_emp where emp_id = ${id}
</select>
</mapper>
2.2 数据输入
2.2.1 传入单个简单数据类型
key名可以任意指定
<delete id="deleteById">
delete from t_emp where emp_id = #{id123}
</delete>
<select id="queryBySalary" resultType="com.landy.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary from t_emp where emp_salary = #{salary}
</select>
2.2.2 传入单个实体数据类型
传入对象时,key名需要对应为对象的属性名(严格对应)
<insert id="insertEmp">
insert into t_emp(emp_id, emp_name, emp_salary) values(#{empId}, #{empName}, #{empSalary})
</insert>
传入对应的Employee类
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
//getter | setter
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Double getEmpSalary() {
return empSalary;
}
public void setEmpSalary(Double empSalary) {
this.empSalary = empSalary;
}
}
2.2.3 多个简单数据类型
有多个简单数据类型时,key值不可以随便传入!
方案1:(推荐)
@Param(value="keyName")注解指定
List<Employee> queryByNameAndSalary(@Param("name") String name,@Param("salary") Double salary);
<select id="queryByNameAndSalary" resultType="com.landy.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary from t_emp where emp_name = #{name} and emp_salary = #{salary}
</select>
方案2:
MyBatis默认机制:从左至右按顺序依次传入 name = param1/args0, salary = param2/args1
<select id="queryByNameAndSalary" resultType="com.landy.pojo.Employee">
select emp_id empId, emp_name empName, emp_salary empSalary
from t_emp where emp_name = #{param1} and emp_salary = #{param2}
</select>
2.2.4 Map数据类型
传入的keyName与Map的keyName对应即可
<insert id="insertEmpMap">
insert into t_emp(emp_name, emp_salary) values (#{name}, #{salary})
</insert>
2.3 数据输出
2.3.1 概述
数据输出:resultType一般有两种形式:
增、删、改操作所影响的行数:返回值为int类型
查询操作的查询结果所对应的数据类型
2.3.2 单个简单类型
resultType = "类的全限定符" / “别名简称”。
<delete id="deleteById">
delete from t_emp where emp_id = #{id};
</delete>
<!-- resultType语法:类的全限定符 / 别名简称 -->
<!-- 如果没有别名,需要声明类的全限定符号,或者自己声明别名 -->
<select id="queryById" resultType="int">
select emp_name empName from t_emp where emp_id = #{id}
</select>
如果自定义类没有别名,可以自己声明别名:
<settings>标签后,<environments>标签前,声明<typeAlias>标签。
<typeAliases>
<typeAlias type="com.landy.pojo.Employee" alias="emp" />
</typeAliases>
或通过指定包名,自动将类名首字母小写的名称作为别名Alias。 (批量定义)
<typeAliases>
<package name="com.landy.pojo"/>
</typeAliases>
同时,批量设置后,可以使用@Alias("otherName"),把默认的首字母小写别名改为指定的otherName,如在Employee类上方声明@Alias("name")即可把emp作为别名
2.3.3 返回实体对象类型
resultType = "返回类型的全限定符" / "别名"
要求:
返回单个实体类型时,要求返回的列名和对象实体的属性名保持一致,这样才可以实现属性映射。
设置:
若emp_id 去掉下划线 -> empId 能够与属性名对应,则可以实现属性映射。
<settings>标签中设置如下:
<settings>
...
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
2.3.4 返回Map类型
直接讲resultType声明为"map"即可。列名为key,查询结果为value。
<select id="selectEmpNameAndSalary" resultType="map">
select emp_name, emp_salary from t_emp where emp_id = #{id};
</select>
Map<String,Object> selectEmpNameAndSalary(int id);
2.3.5 返回List类型
如果返回值有多个同类型的实体对象,需要用List集合承接,resultType类型无需声明为List,声明为集合类对应的泛型,及同类型的实体对象即可。
<select id="queryEmpNameBySalary" resultType="String">
select emp_name from t_emp where emp_salary > #{salary}
</select>
<select id="queryAllEmp" resultType="Employee">
select * from t_emp;
</select>
// 查询工资高于传入值的员工姓名
List<String> queryEmpNameBySalary(double salary);
// 查询全部员工
List<Employee> queryAllEmp();
因为MyBatis框架底层都是按照selectList方法进行查询,即都是按照集合去查询,故resultType只要声明为泛型类即可!
2.3.6 返回主键值
插入对象时想获得对象primary_key的value值用于后续操作:需要返回主键值。
当主键auto increament时,<insert>标签中声明属性:
userGeneratedKeys="true":需要数据库自增长的主键值
keyColumn="emp_id":主键列的名称
keyProperty="empId":接收主键列值得属性
<insert id="insertEmp" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">
insert into t_emp(emp_name, emp_salary) values(#{empName}, #{empSalary})
</insert>
当主键没有自增长时:
<insert>标签内声明<selectKey>标签:在插入之前先指定一段sql语句用于生成主键值
<selectKey order="BEFORE" resultType="" keyProperty="">
order:声明selectKey中得语句在插入语句前或后执行 value="BEFORE" | "AFTER"
resultType:返回值类型
keyProperty:查询结果给哪个动态key赋值
<!-- 希望mybatis帮忙维护非自增长得主键 -->
<insert id="insertTeacher">
<selectKey keyProperty="tId" resultType="String" order="BEFORE">
select uuid()
</selectKey>
insert into teacher(t_id, t_name)
values (#{tId}, #{tName})
</insert>
2.3.7 实体类属性
<!--
列名和属性名不一致如何解决?
1. 起别名,使列名与属性名对应
2. 开始驼峰映射:<setting name="mapUnderscoreToCamelCase" value="true"/>
3. resultMap自定义映射,
vs:resultType按照规则自动映射,只能映射一层结构
-->
<!--
id:resultMap的唯一标识,其他组件引用
type:具体的返回值类型
<id>:主键映射关系
<result>:普通映射关系
-->
<resultMap id="tMap" type="teacher">
<id column="t_id" property="tId"/>
<result column="t_name" property="tName"/>
</resultMap>
<select id="queryById" resultMap="tMap">
select * from teacher where t_id = #{id}
</select>
resultMap:自定义属性映射方式,实现深层次映射
id:resultMap的唯一标识,其他组件引用id以引用map组件
tyep:返回值对应类型:别名 | 全限定符 | 泛型
<id column="primary_key主键列" property="对应属性名">
<result column="其他列" property="对应属性名">