Mybatis SQL映射文件详解
前文:
Mybatis的介绍和基本使用
在mybatis映射文件中,可以编写以下的顶级元素标签:
cache – 该命名空间的缓存配置。
cache-ref – 引用其它命名空间的缓存配置。
resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
sql – 可被其它语句引用的可重用语句块。
insert – 映射插入语句。
update – 映射更新语句。
delete – 映射删除语句。
select – 映射查询语句。
在每个顶级元素标签中可以添加很多个属性,下面了解下具体的配置。
1、insert、update、delete元素
属性 | 描述 |
---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap |
用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。 |
flushCache |
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。 |
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)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
databaseId |
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
<!--如果数据库支持自增可以使用这样的方式-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into user(user_name) values(#{userName})
</insert>
<!--如果数据库不支持自增的话,那么可以使用如下的方式进行赋值查询-->
<insert id="insertUser2" >
<selectKey order="BEFORE" keyProperty="id" resultType="integer">
select max(id)+1 from user
</selectKey>
insert into user(id,user_name) values(#{id},#{userName})
</insert>
2、select元素
首先定义UserDao.java
package com.example.dao;
import com.example.bean.Emp;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface EmpDao {
public Emp findEmpByEmpno(Integer empno);
public int updateEmp(Emp emp);
public int deleteEmp(Integer empno);
public int insertEmp(Emp emp);
Emp selectEmpByNoAndName(@Param("empno") Integer empno, @Param("ename") String ename,@Param("t") String tablename);
Emp selectEmpByNoAndName2(Map<String,Object> map);
List<Emp> selectAllEmp();
Map<String,Object> selectEmpByEmpReturnMap(Integer empno);
@MapKey("empno")
Map<Integer,Emp> getAllEmpReturnMap();
}
1、select的参数传递
EmpDao.xml
<!--
当查询语句中包含多个参数时,如果使用#{属性名称}就无法获取具体的值了,那么应该如何使用呢?
下面就是mybatis的参数传递方式
1、如果是单个参数,
基本类型:使用#{随便写}
引用类型:使用#{类的属性名称}
2、多个参数:
当查询的时候传入多个参数的时候,就无法简单的通过#{参数名}来获取值了,
只能通过arg0,arg1...或者param1,param2等方式来获取值
原因就在于,mybatis在传入多个参数的时候,会将这些参数封装到一个map中,此时map中的key就是
arg0,arg1,param1,param2这些值,但是很明显,这样的传值方式不是很友好,没有办法根据参数的名称来
获取具体的值,因此可以使用如下的方式来指定参数的key是什么
Emp selectEmpByNoAndName(@Param("empno") Integer empno, @Param("ename") String ename);
也就是通过@Param来指定存入map中的key值是什么
3、使用map来传递参数:
依然是直接使用#{key}来获取具体的属性值
-->
<select id="selectEmpByNoAndName" resultType="com.example.bean.Emp">
select * from emp where empno=#{empno} and ename=#{ename}
</select>
<select id="selectEmpByNoAndName2" resultType="com.example.bean.Emp">
select * from emp where empno=#{empno} and ename=#{ename}
</select>
2、参数的取值方式
在xml文件中编写sql语句的时候有两种取值的方式,分别是#{}和${},下面来看一下他们之间的区别:
EmpDao.xml
<!--
当使用#{}来获取值的时候会发现打印的sql语句如下:
select * from emp where empno=? and ename=?
当使用${}来获取值的时候会发现打印的sql语句如下:
select * from emp where empno=7369 and ename='SMITH'
通过刚刚的案例发现了存在的问题:
使用#{}方式进行取值:采用的是参数预编译的方式,参数的位置使用?进行替代,不会出现sql注入的问题
使用${}方式进行取值:采用的是直接跟sql语句进行拼接的方式
此处需要注意,如果sql语句中的某些值不支持参数预编译,那么就必须要使用${}的方式来取值了
-->
<select id="selectEmpByNoAndName" resultType="com.example.bean.Emp">
select * from #{t} where empno=${empno} and ename=${ename}
</select>
3、处理集合返回结果—resultType
EmpDao.xml
<!--1.当返回值的结果是集合的时候,返回值的类型依然写的是集合中具体的类型-->
<select id="selectAllEmp" resultType="com.example.bean.Emp">
select * from emp
</select>
<!--2.在查询的时候可以设置返回值的类型为map,当mybatis查询完成之后会把列的名称作为key
列的值作为value,转换到map中
-->
<select id="selectEmpByEmpReturnMap" resultType="map">
select * from emp where empno = #{empno}
</select>
<!--3.当返回的结果是一个集合对象的是,返回值的类型一定要写集合具体value的类型
同时在dao的方法上要添加@MapKey的注解,来设置key是什么结果
@MapKey("empno")
Map<Integer,Emp> getAllEmpReturnMap();-->
<select id="getAllEmpReturnMap" resultType="com.example.bean.Emp">
select * from emp
</select>
4、自定义结果集—resultMap
Dog.java
package com.example.bean;
public class Dog {
private Integer id;
private String name;
private Integer age;
private String gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Dog{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
dog.sql
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `dog`
-- ----------------------------
DROP TABLE IF EXISTS `dog`;
CREATE TABLE `dog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dname` varchar(255) DEFAULT NULL,
`dage` int(11) DEFAULT NULL,
`dgender` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of dog
-- ----------------------------
INSERT INTO dog VALUES ('1', '大黄', '1', '雄');
INSERT INTO dog VALUES ('2', '二黄', '2', '雌');
INSERT INTO dog VALUES ('3', '三黄', '3', '雄');
DogDao.java
package com.example.dao;
import com.example.bean.Dog;
public interface DogDao {
public Dog selectDogById1(Integer id);
public Dog selectDogById2(Integer id);
}
DogDao.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.example.dao.DogDao">
<!--
在使用mybatis进行查询的时候,mybatis默认会进行结果的封装,但是要求列名跟属性名称一一对应上
在实际的使用过程中,会发现有时候数据库中的列名跟类中的属性名并不是一一对应的,此时就需要起别名
起别名有两种实现方式:
1、在编写sql语句的时候添加别名
2、自定义封装结果集
-->
<!--可以在sql语句中写别名-->
<select id="selectDogById1" resultType="com.example.bean.Dog">
select id id,dname name,dage age,dgender gender from dog where id = #{id}
</select>
<!--这种方式是查询不到任何结果的,因为属性名跟列名并不是一一对应的-->
<!-- <select id="selectDogById" resultType="com.example.bean.Dog">
select * from dog where id = #{id}
</select>-->
<!--自定义结果集,将每一个列的数据跟javaBean的对象属性对应起来
type:表示为哪一个javaBean对象进行对应
id:唯一标识,方便其他属性标签进行引用
-->
<resultMap id="myDog" type="com.example.bean.Dog">
<!--
指定主键列的对应规则:
column:表示表中的主键列
property:指定javaBean的属性
-->
<id column="id" property="id"></id>
<!--设置其他列的对应关系-->
<result column="dname" property="name"></result>
<result column="dage" property="age"></result>
<result column="dgender" property="gender"></result>
</resultMap>
<!--根据查询的数据进行结果的封装要使用resultMap属性,表示使用自定义规则-->
<select id="selectDogById2" resultMap="myDog">
select * from dog where id = #{id}
</select>
</mapper>
5、联合查询
emp.java
package com.example.bean;
import java.util.Date;
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double common;
private Dept dept;
public Emp() {
}
public Emp(Integer empno, String ename) {
this.empno = empno;
this.ename = ename;
}
public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, Double sal, Double common, Dept dept) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.mgr = mgr;
this.hiredate = hiredate;
this.sal = sal;
this.common = common;
this.dept = dept;
}