MyBatis Mapper映射文件配置的实现
目录
- 常用属性标签
- namespace的作用
- 常用标签介绍
- parametetType属性
- resultType属性
- resultMap
- sql
- 数据输入
- 在SQL语句中获取参数
- #{}的方式
- ${}的方式
- 单个简单类型参数
- 多个简单类型参数
- 实体类类型参数
- Map类型参数
- 数据输出
- 返回单个简单类型数据
- 返回一条数据
- 返回实体类对象
- 返回Map类型
- 返回多行数据
- 返回List<POJO>
- 返回List<Map>
- 返回自增主键
- 使用场景
- 实现方案
- 不支持自增主键的数据库怎么获取主键值
- 结果集的字段和实体类属性对应关系
- 自动映射
- 全局配置自动识别驼峰式命名规则
- 手动映射
- 多表关联查询
- 物理建模
- 一对一或多对一查询
- 一对多查询
常用属性标签
namespace的作用
在MyBATis中,Mapper中的namespace用于绑定Dao接口的,即面向接口编程。 namespace属性的值要和对应的Mapper接口的全限定名保持一致。
namespace的好处在于当使用了namespace之后就可以不用写接口实现类,业务逻辑会直接通过这个绑定寻找到相对应的SQL语句进行对应的数据处理。
常用标签介绍
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
- sql – 可被其他语句引用的可重用语句块
- resultMap - 确定实体类属性与表中字段对应关系
parametetType属性
在<insert>,<update>,<select>,<delete>
标签中,可以通过parameterType
指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型
。
parameterType
属性是可以省略
的,MyBatis框架
可以根据SqlSession
接口中方法的参数来判断输入参数的实际数据类型。
resultType属性
- resultType属性存在标签.负责将查询结果进行映射。
- resultType属性可以指定一个基本类型也可以是一个实体类类型。
- resultType属性无法与
resultMap属性
同时出现。
resultMap
MyBatis框架中是根据表中字段名到实体类定位同名属性的.如果出现了实体类属性名与表中字段名不一致的情况,则无法自动进行对应.此时可以使用resultMap来重新建立实体类与字段名之间对应关系
<!--mybatis-config文件配置,可以为一些类定义别名--> <!--<typeAliases> <typeAlias type="com.xyxy.pojo.Emp" alias="emp"></typeAlias> </typeAliases>--> <!-- type属性里面使用别名就可以不用全路径 --> <resultMap id="empMapper" type="emp"> <id property="empId" column="emp_id"></id> <result property="empName" column="emp_name"></result> <result property="empSalary" column="emp_salary"></result> </resultMap> <select id="findAll" resultMap="empMapper"> select * from t_emp </select>
sql
sql:
里面可以写入一个共同的sql代码,用于提取重复的代码。 要使用该代码的时候就直接使用标签id:
为提取的sql代码,取一个id,起标识作用
<!-- 公共代码 --> <sql id="select"> <!-- select * from t_emp --> select emp_id empId,emp_name empName,emp_salary empSalary from t_emp </sql> <!--select标签的id与接口的方法名对应,resultType和返回结果封装的Bean一致--> <select id="findById" resultType="com.xyxy.pojo.Emp"> <!-- include:用于加载提取公共的sql语句,与<sql>标签对应 refid:填写<sql>标签中的id属性--> <include refid="select"></include> where emp_id=#{empId} </select> <select id="findByIdOrName" parameterType="Emp" resultType="emp"> <!-- 引入公共代码 --> <include refid="select"></include> <!-- where标签:一个where条件语句,通常和<if>标签混合使用 --> <where> <!-- if标签:执行一个判断语句,成立才会执行标签体内的sql语句,test:写上条件判断语句 注意:这里每一个if前面都尽量加上and,如果你是第一个条件,框架会自动帮你把and截取, 如果是第二个if就不能省略and--> <if test="empId != null and empId != ''"> and emp_id=#{empId} </if> <if test="empName != null and empName != ''"> and emp_name like '%${empName}%' </if> </where> </select>
数据输入
在SQL语句中获取参数
#{}的方式
Mybatis会在运行过程中,把配置文件中的SQL语句里面的 #{}转换为?
占位符,发送给数据库执行。
配置文件中的SQL
<delete id="deleteEmployeeById" parameterType="int"> delete from t_emp where emp_id=#{empId} </delete>
实际执行的SQL
delete from t_emp where emp_id=?
${}的方式
Mybatis会在运行过程中, 将来会根据${}
拼字符串
配置文件中的SQL语句
<select id="selectEmployeeByName" resultType="com.xyxy.pojo.Employee"> select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_name like '%${empName}%' </select>
Mapper接口
注意:由于Mapper接口中方法名是作为SQL语句标签的id,不能重复,所以Mapper接口中不能出现重名的方法,不允许重载!
#{}
:采用预编译方式,可以防止SQL注入${}
:采用直接赋值方式,无法阻止SQL注入攻击
单个简单类型参数
Mapper接口中的抽象方法
Employee selectEmployee(Integer empId);
映射配置文件:此时SQL语句中获取参数#
<select id="selectEmployee" resultType="com.xyxy.pojo.Employee"> select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId} </select>
多个简单类型参数
Mapper接口中抽象方法:
此时每个方法需要使用Param注解命名
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>
实体类类型参数
Mapper接口中抽象方法:
int insertEmployee(Employee employee);
映射配置文件:
此时SQL语句获取参数#{getXXX方法对应的名字,首字母改小写}
<insert id="insertEmployee"> insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary}) </insert>
Mybatis会根据#{}
中传入的数据,加工成getXxx()
方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}这个位置。
Map类型参数
Mapper接口中抽象方法:
int updateEmployeeByMap(Map<String, Object> paramMap);
映射配置文件:
此时SQL语句获取参数#
<update id="updateEmployeeByMap"> update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey} </update>
数据输出
数据输出是针对查询数据的方法返回查询结果
返回单个简单类型数据
Mapper接口中的抽象方法:
方法的返回值是简单数据类型
/** * 统计员工数量 * @return */ Long selectEmployeeCount();
映射配置文件:
此时标签的resultType
的类型对应抽象方法的返回值类型
<!-- 返回简单类型: resultType表示结果类型:结果集返回的类型,要和Mapper接口中对应的方法的返回值类型保持一致 --> <select id="selectEmployeeCount" resultType="long"> select count(emp_id) from t_emp </select>
返回一条数据
返回实体类对象
Mapper接口中的抽象方法:
方法的返回值是POJO
类型
Employee selectEmployee(Integer empId);
映射配置文件:
此时标签的resultType的类型对应抽象方法的返回值类型的全限定名
<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 --> <!-- resultType属性:指定封装查询结果的Java实体类的全类名 --> <select id="selectEmployee" resultType="com.xyxy.pojo.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>
返回Map类型
适用于SQL查询返回的各个字段综合起来并不和任何一个现有的实体类对应,没法封装到实体类对象中。能够封装成实体类类型的,就不使用Map类型。
Mapper接口中的抽象方法:
方法的返回值是Map类型
/** * 根据empId查询员工信息,python并且将结果集封装到Map中 * @param empId * @return */ Map selectEmployeeMapByEmpId(Integer empId);
映射配置文件:
此时标签的resultType
的类型为map
<!-- 返回Map类型: resultType表示结果类型: 就是Map的全限定名或者别名 --> <select id="selectEmployeeMapByEmpId" resultType="map"> select * from t_emp where emp_id=#{empId} </select>
返回多行数据
返回List<POJO>
查询结果返回多个实体类对象,希望把多个实体类对象放在List集合中返回。此时不需要任何特殊处理,在resultType属性中还是设置实体类类型即可。
Mapper接口中的抽象方法:
方法的返回值是List<POJO>
List<Employee> selectAll();
映射配置文件:
此时标签的resultType
的类型为POJO类
的全限定名
<!-- List<Employee> selectAll(); --> <select id="selectAll" resultType="com.xyxy.pojo.Employee"> select emp_id empId,emp_name empName,emp_salary empSalary from t_emp </select>
返回List<Map>
查询结果返回多个Map对象,希望把多个Map对象放在List集合中返回。此时不需要任何特殊处理,在resultType属性中还是设置map即可。
Mapper接口中的抽象方法:
方法的返回值是List<Map>
类型
List<Map> selectAllMap();
映射配置文件:
此时标签的resultType
的类型为map
<select id="selectAllMap" resultType="map"> select emp_id empId,emp_name empName,emp_salary empSalary from t_emp </select>
返回自增主键
使用场景
例如:保存订单信息。需要保存Order对象和List<OrderItem>
。其中,OrderItem
对应的数据库表,包含一个外键,指向Order对应表的主键。
在保存List<OrderItem>
的时候,需要使用下面的SQL:
insert into t_order_item(item_name,item_price,item_count,order_id) values(...)
这里需要用到的order_id
,是在保存Order对象
时,数据库表以自增方式
产生的,需要特殊办法拿到这个自增的主键值。
实现方案
Mapper接口中的抽象方法:
int insertEmployee(Employee employee);
映射配置文件:
<!-- 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); //打印自动返回存入对象的主键值 System.out.println("employee.getEmpId() = " + employee.getEmpId()); }
注意:
Mybatis是将自增主键的值设置到实体类对象中,而不是以Mapper接口方法返回值的形式返回。
另一种做法
<insert id="insertEmployee"> insert into t_emp (emp_name,emp_salary) values (#{empName},#{empSalary}) <!-- keyColumn="emp_id"表示要查询的主键的列名 keyProperty="empId"表示将查询到的主键值赋给JavaBean的哪个属性 resultType="int"表示查询的结果类型 order="AFTER" 表示这个查询是执行在insert之前还是之后呢?如果为AFTER表示之后,BEFORE表示之前 --> <selectKey keyColumn="emp_id" keyProperty="empId" resultType="int" order="AFTER"> select last_insert_id() </selectKey> </insert>
不支持自增主键的数据库怎么获取主键值
而对于不支持自增型主键的数据库(例如 oracle),则可以使用 selectKey 子元素:selectKey元素将会首先运行
,id
会被设置,然后插入语句会被调用
<insert id="insertEmployee" parameterType="com.atguigu.mybatis.beans.Employee" databaseId="oracle"> <selectKey order="BEFORE" keyProperty="id" resultType="integer"> select employee_seq.nextval from dual </selectKey> insert into orcl_employee(id,last_name,email,gender) values(#{id},#{lastName},#{email},#{gender}) </insert>
或者:
<insert id="insertEmployee" parameterType="com.atguigu.mybatis.beans.Employee" databaseId="oracle"> <selectKey order="AFTER" keyProperty="id" resultType="integer"> select employee_seq.currval from dual </selectKey> insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName},#{email},#{gender}) </insert>
结果集的字段和实体类属性对应关系
自动映射
Mybatis
在做结果集与POJO
类的映射关系的时候,会自动将结果集的字段名与POJO
的属性名(其实是和getXXX方法
)进行对应映射,结果集的数据会自动映射给POJO
对象中同名的属性;
POJO
属性名不一致的情况,我们可以在编写查询语句的时候,给结果集的字段取别名,让别名与POJO
的属性名一致以保证结果集的正确映射
全局配置自动识别驼峰式命名规则
因为我们表中字段的命名规则采用_
,而POJO
的属性名命名规则采用驼峰命名法,所以导致我们在执行查询语句的时候总是要对查询的字段取别名,以确保正确地进行结果集映射
Mybatis框架
当然也注意到了这个问题,所以它提供了一种自动识别驼峰命名规则的配置,我们只要做了该配置,那么全局的所有查询语句的执行都会自动识别驼峰命名规则
在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>
手动映射
使用resultMap
标签手动指定结果集字段与POJO
属性的映射关系,可以非常灵活地进行结果集的映射
<!-- 手动映射:通过resultMap标签配置映射规则 1. id属性:表示这个手动映射规则的唯一表示 2. type属性: 表示这个手动映射规则是将结果集映射给哪个类的对象,就是JavaBean类的全限定名 resultMap标签中的子标签就是一一指定映射规则: 1. id标签:指定主键的映射规则 2. result标签:指定非主键的映射规则 id标签和result标签的属性: 1. column:要进行映射的结果集的字段名 2. property:要进行映射的JavaBean的属性名 --> <resultMap id="EmployeeInfoMap" type="com.xyxy.pojo.EmployeeInfo"> <id column="emp_id" property="id"/> <result column="emp_name" property="name"/> <result column="emp_salary" property="salary"/> </resultMap> <!-- 在select标签中通过resultMap属性来指定使用哪个手动映射规则 --> <select id="selectEmployeeInfoByEmpId" resultMap="EmployeeInfoMap"> select * from t_emp where emp_id=#{empId} </select>
多表关联查询
物理建模
CREATE TABLE `t_customer` ( `customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) ); CREATE TABLE `t_order` ( `order_id` INT NOT NULL AUTO_INCREMENT, `order_name` CHAR(100), `customer_id` INT, PRIMARY KEY (`order_id`) ); INSERT INTO `t_customer` (`customer_name`) VALUES ('c01'); INSERT INTO `t_customer` (`customer_name`) VALUES ('c02'); INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1'); INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1'); INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o4', '2'); INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o5', '2');
t_customer
表和t_order
表示一对多关系,反之t_order
表和t_customer
表可以看成一对一或者多对一关系
一对一或多对一查询
任务
根据订单ID查询出订单信息,并且查询出该订单所属的顾客信息,将查询到的结果集封装到Order对象中
POJO封装结果集
public class Order { private Integer orderId; private String orderName; //表示Order和Customer的对一关系 javascript private Customer customer; } public class Customer { private Integer customerId; private String customerName; }
接口方法
public interface OrderMapper{ Order findByOrderId(Integer orderId); }
在全局配置文件中配置
<!--全局配置自动映射驼峰命名--> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!--实体类取别名--> <typeAliases> <package name="com.xyxy.pojo"/> &lDQLoErt;/typeAliases> <!-- Mapper注册:指定Mybatis映射文件的具体位置 --> <!-- mappers标签:配置一个具体的Mapper映射文件 --> <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录 <mappers> <!-- 包下的所有Mapper配置文件将被自动加载、注册,比较方便。 --> <package name="com.xyxy.mapper"/> </mappers>
映射配置文件OrderMapper.XML
<?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="com.xyxy.mapper.OrderMapper"> <resultMap id="order" type="Order" autoMapping="true"> <!-- autoMapping属性设置为true开启自动映射 --> <association property="customer" javaType="Customer"> <id column="customer_id" property="customerId"></id> <result column="customer_name" property="customerName"></result> </association> </resultMap> <select id="findByOrderId" resultMap="order"> select * from t_order o left join t_customer c on o.customer_id=c.customer_id where order_id=#{orderId} </select> </mapper>
一对多查询
任务
根据客户的ID查询客户信息,并且查询出该客户的所有订单信息,将查询的订单信息结果集封装到Customer对象中
POJO封装结果集
public class Customer { private Integer customerId; private String编程 customerName; //客户和订单的一对多关系 private List<Order> orderList; } public class Order { private Integer orderId; private String orderName; }
CustomerMapper接口中的抽象方法
public interface CustomerMapper { Customer findCustomerAndOrders(Integer customerId); }
映射配置文件CustomerMapper.xml
<?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="com.xyxy.mapper.CustomerMapper"> <resultMap id="customer" type="Customer" > <id column="customer_id" property="customerId"/> <result column="customer_name" property="customerName"/> <collection property="orderList" ofType="Order" autoMapping="true"> <!-- 进行一对多映射,使用collection标签 ofType属性指的是orderList的泛型 --> </collection> </resultMap> <select id="findCustomerAndOrders" resultMap="customer"> SELECT * FROM t_customer c,t_order o WHERE o.customer_id=c.candroidustomer_id AND c.customer_id=#{customerId} </select> </mapper>
到此这篇关于MyBatis Mapper映射文件配置的实现那的文章就介绍到这了,更多相关MyBatis Mapper映射文件配置内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论