010-Mybatis基础

介绍

MyBatis是一个支持普通SQL查询、存储过程、高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。

快速入门

使用到Maven+Mybatis+log4j+generator+lombok,最终实现的文件目录结构如下:
ef7f5d7014f41d992fe8bd406ca7c3a5
pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.co.webapp</groupId>
<artifactId>webapp</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<!--generator配置文件生成路径-->
<targetJavaProject>${basedir}/src/main/java</targetJavaProject>
<targetMapperPackage>com.co.webapp.mapper</targetMapperPackage>
<targetModelPackage>com.co.webapp.entity</targetModelPackage>
<targetResourcesProject>${basedir}/src/main/resources</targetResourcesProject>
<targetResourcesPackage>mapper</targetResourcesPackage>
</properties>

<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
</dependencies>

<build>
<plugins>
<!-- mvn mybatis-generator:generate -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<!-- generate指定数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

db.properties:数据库配置文件

1
2
3
4
5
6
7
8
9
10
11
#Mysql配置
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
name=root
password=12345678

#Oracle配置
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@erptest-db.gz.cvte.cn:1531/erptest
#name=
#password=

log4j.properties:log4j配置文件
MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。它会使用第一个查找得到的工具(优先级从高到低:SLF4J、Apache Commons Logging、Log4j 2、Log4j、JDK logging)。如果一个都未找到,日志功能就会被禁用。

1
2
3
4
5
log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.org.apache=INFO

mybatis-config.xml:Mybatis配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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>
<!-- 引用db.properties配置文件 -->
<properties resource="db.properties"/>

<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/><!--自动驼峰命名转换-->
<setting name="logImpl" value="LOG4J"/><!--指定使用LOG4J日志-->
</settings>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<!-- value属性值引用db.properties配置文件中配置的值 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${name}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 注册mapper文件-->
<mappers>
<mapper resource="mapper/EMPMapper.xml"/>
</mappers>
</configuration>

generatorConfig.xml:Generator配置文件
Mybatis属于半自动ORM,在使用这个框架中,工作量最大的就是书写Mapping的映射文件,由于手动书写很容易出错,可以利用Mybatis-Generator来帮我们自动生成Dao、Model、Mapping相关文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 引用db.properties配置文件 -->
<properties resource="db.properties"/>

<!-- 数据库驱动,pom中加入插件时已经配置jdbc,此处无需配置-->
<!-- <classPathEntry location="D:\generator\mysql-connector-java-8.0.16.jar" /> -->

<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>

<!-- 数据库配置 -->
<jdbcConnection driverClass="${driver}" connectionURL="${url}"
userId="${name}" password="${password}">
</jdbcConnection>

<javaTypeResolver>
<!-- true:使用BigDecimal对应DECIMAL和 NUMERIC数据类型
false:默认,
scale>0;length>18:使用BigDecimal;
scale=0;length[10,18]:使用Long;
scale=0;length[5,9]:使用Integer;
scale=0;length<5:使用Short;-->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>

<!-- 【entity】生成模型的包名和位置 -->
<javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}">
<!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
<property name="enableSubPackages" value="false"/>
<!-- 设置是否在getter方法中,对String类型字段调用trim()方法 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>

<!-- 【xml】生成的映射文件包名和位置 -->
<sqlMapGenerator targetPackage="${targetResourcesPackage}" targetProject="${targetResourcesProject}">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>

<!-- 【接口】生成DAO的包名和位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="${targetMapperPackage}"
targetProject="${targetJavaProject}">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>

<!--
tableName(必要):要生成对象的表名;
可选:
1,schema:数据库的schema;
2,catalog:数据库的catalog;
3,alias:为数据表设置的别名,如果设置了alias,那么生成的所有的SELECT SQL语句中,列名会变成:alias_actualColumnName
4,domainObjectName:生成的domain类的名字,如果不设置,直接使用表名作为domain类的名字;可以设置为somepck.domainName,那么会自动把domainName类再放到somepck包里面;
5,enableInsert(默认true):指定是否生成insert语句;
6,enableSelectByPrimaryKey(默认true):指定是否生成按照主键查询对象的语句(就是getById或get);
7,enableSelectByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询语句;
8,enableUpdateByPrimaryKey(默认true):指定是否生成按照主键修改对象的语句(即update);
9,enableDeleteByPrimaryKey(默认true):指定是否生成按照主键删除对象的语句(即delete);
10,enableDeleteByExample(默认true):MyBatis3Simple为false,指定是否生成动态删除语句;
11,enableCountByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询总条数语句(用于分页的总条数查询);
12,enableUpdateByExample(默认true):MyBatis3Simple为false,指定是否生成动态修改语句(只修改对象中不为空的属性);
13,modelType:参考context元素的defaultModelType,相当于覆盖;
14,delimitIdentifiers:参考tableName的解释,注意,默认的delimitIdentifiers是双引号,如果类似MYSQL这样的数据库,使用的是`(反引号,那么还需要设置context的beginningDelimiter和endingDelimiter属性)
15,delimitAllColumns:设置是否所有生成的SQL中的列名都使用标识符引起来。默认为false,delimitIdentifiers参考context的属性
-->
<table schema="test" tableName="EMP" domainObjectName="EMP"
enableSelectByPrimaryKey="true" enableSelectByExample="false" enableInsert="false"
enableUpdateByPrimaryKey="false" enableDeleteByPrimaryKey="false" enableDeleteByExample="false"
enableCountByExample="false" enableUpdateByExample="false"/>
</context>
</generatorConfiguration>

配置完打开Maven,右键执行Generator
35af646a5c2e5aae37bc92ae55f63e4e
执行完项目下自动生成了3个文件,省去了我们手写:下划线转驼峰的的EMP.java,数据库字段与实体字段映射关系的EMPMapper.xml,一个与EMPMapper.xml匹配的的接口EMPMapper.java
a971e80680cbb3cc6af99790ce0661f1
EMP.java:用于存储数据库返回的数据。删除其他不需要代码,使用lombok注解@Data

1
2
3
4
5
6
7
8
9
10
11
12
package com.co.webapp.entity;
@Data
public class EMP {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Float sal;
private Float comm;
private Integer deptno;
}

EMPMapper.xml:定义执行的SQL
namespace为EMPMapper.java的路径+类名,id为对应的方法名,namespace和id都必须是全局唯一的,入参和出参类型必须与EMPMapper.java保持一致
注:查询SQL语句结尾不能加分号,匿名块可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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.co.webapp.mapper.EMPMapper">
<!-- Mybatis自动映射必须是数据库字段名与实体字段名完全一样,
如果两者不对应,则无法将结果集放入实体中,resultMap主要解决二者映射对应关系 -->
<resultMap id="EMPMap" type="com.co.webapp.entity.EMP">
<result column="empno" jdbcType="INTEGER" property="empno"/>
<result column="ename" jdbcType="VARCHAR" property="ename"/>
<result column="job" jdbcType="VARCHAR" property="job"/>
<result column="mgr" jdbcType="INTEGER" property="mgr"/>
<result column="hiredate" jdbcType="DATE" property="hiredate"/>
<result column="sal" jdbcType="REAL" property="sal"/>
<result column="comm" jdbcType="REAL" property="comm"/>
<result column="deptno" jdbcType="INTEGER" property="deptno"/>
</resultMap>

<!-- statementType参数模式,parameterType参数类型,resultMap返回结果集类型 -->
<select id="queryEMPEname" statementType="PREPARED" parameterType="String" resultMap="EMPMap">
select * from EMP where ENAME = #{ename,mode=IN,jdbcType=VARCHAR}
</select>

<!-- 因配置文件已启用了自动驼峰命名转换,可以不需要resultMap也能自动实现对应 -->
<!--<select id="queryEMPEname" parameterType="String" resultType="com.co.webapp.entity.EMP">
select * from EMP where ENAME = #{ename,mode=IN,jdbcType=VARCHAR}
</select>-->
</mapper>

EMPMapper.java:定义与数据库交互接口

1
2
3
4
5
6
7
8
9
package com.co.webapp.mapper;
public interface EMPMapper {
//方式一:xml
public List<EMP> queryEMPEname(@Param("ename") String ename);

//方式二:注解
@Select("select * from EMP where EMPNO = #{empno,mode=IN,jdbcType=VARCHAR}")
public List<EMP> queryEMPEmpno(int empno);
}

MybatisUtil.java:公用的Mybatis工具类,可以减少代码,配置公用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.co.webapp.base;
public class MybatisUtil {
/**
* @Method getSqlSessionFactory
* @Param []
* @Return org.apache.ibatis.session.SqlSessionFactory
**/
public static SqlSessionFactory getSqlSessionFactory() {
String resource = "mybatis-config.xml"; //必须放在resources下,不然无法加载到
InputStream is = MybatisUtil.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
return factory;
}

/**
* @Method getSqlSession
* @Param []
* @Return org.apache.ibatis.session.SqlSession
**/
public static SqlSession getSqlSession() {
return getSqlSessionFactory().openSession();
}

/**
* @Method getSqlSession
* @Param [isAutoCommit]:true 自动提交事务,false 不自动提交事务
* @Return org.apache.ibatis.session.SqlSession
**/
public static SqlSession getSqlSession(boolean isAutoCommit) {
return getSqlSessionFactory().openSession(isAutoCommit);
}
}

Test.java:测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.co.webapp;
public class Test {
@org.junit.Test
public void EMPQueryTest() throws IOException {
//方式一:基于MybatisUtil+XML接口实现
//创建能执行映射文件中sql的sqlSession
SqlSession sqlSession1 = MybatisUtil.getSqlSession(true);//参数:true,表示自动提交
//得到EMPMapper接口的实现类对象,EMPMapper接口的实现类对象由sqlSession.getMapper动态构建出来
EMPMapper mapper1 = sqlSession1.getMapper(EMPMapper.class);
List<EMP> empList1 = mapper1.queryEMPEname("SMITH");
sqlSession1.close();
System.out.println("基于MybatisUtil+XML接口实现:" + empList1);

//方式二:基于MybatisUtil+注解实现
SqlSession sqlSession2 = MybatisUtil.getSqlSession(true);
EMPMapper mapper2 = sqlSession2.getMapper(EMPMapper.class);
List<EMP> empList2 = mapper2.queryEMPEmpno(7499);
sqlSession2.close();
System.out.println("基于MybatisUtil+注解接口实现:" + empList2);

//方式三:基于加载器+XML实现
String resource = "mybatis-config.xml";
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession3 = sessionFactory.openSession(true);
String statement = "com.co.webapp.mapper.EMPMapper.queryEMPEname";//namespace+id
List<EMP> empList3 = sqlSession3.selectList(statement, "WARD");
sqlSession3.close();
System.out.println("基于加载器+XML实现:" + empList3);
}
}

执行结果:
e4c32c09770f004114d515cd8a764867

参数

以#{userId,mode=IN,jdbcType=INTEGER}举例:

  • mode:声明参数方式(IN、OUT、INOUT)
  • jdbcType:声明入参类型
  • 如果接口入参写了@Param(“userId”)或入参类型为Map、实体等,则可用对应的key做别名
  • 如果没写,则可用 #{0} 、 #{1}这样默认顺序声明参数

参数中#{}和${}区别:

  • #{}:Mybatis拼装sql时会自动对参数添加单引号’’ ,如传入的参数为123,会变成’123’
  • ${}:Mybatis不对参数做任何转换,一般用于传入表名或字段名使用,可能导致SQL注入,使用$需要同时指定属性statementType=”STATEMENT”,开启非预编译模式。

标签

select、insert、update、delete

  • parameterType:参数类型,如:实体(com.co.webapp.entity.EMP)、int
  • resultType :返回类型,如:实体(com.co.webapp.entity.EMP)、Map、List
  • resultMap:返回类型,如果查询出来的列名和实体属性名不一致,可以定义resultMap对数据库字段名和实体属性名指定映射关系。注:resultType 与resultMap 不能并用
1
2
3
4
5
6
7
8
<mapper namespace="com.co.webapp.mapper.EMPMapper">
<resultMap id="EMPMap" type="com.co.webapp.entity.EMP">
<result column="empno" jdbcType="INTEGER" property="empno"/>
</resultMap>
<select id="queryEMP" statementType="PREPARED" parameterType="String" resultMap="EMPMap">
select * from EMP where ENAME = #{0}
</select>
</mapper>

if

通常用于WHERE语句中,通过判断参数值来决定是否使用某个查询条件

1
2
3
4
5
6
7
<update id="updateEMP" parameterType="com.co.webapp.entity.EMP">
UPDATE EMP SET ENAME = #{ename,mode=IN,jdbcType=VARCHAR}
WHERE 1 = 1
<if test="empno != null and empno != ''">
AND EMPNO = #{empno,mode=IN,jdbcType=VARCHAR}
</if>
</update>

foreach

主要用于构建in条件,实现在sql中对集合进行迭代,注:如果collection参数为空就无法完成拼接SQL会报错,可以用if来先做是否为空的判断
主要属性:

  • collection:类型可以为list、array数组、map
  • item:表示集合中每一个元素进行迭代时的别名
  • index:指代每次迭代坐标位置
  • open:表示语句以什么开始
  • separator:表示在每次进行迭代之间以什么符号作为分隔符
  • close:表示语句以什么结束

批量查询

1
2
3
4
5
6
7
8
9
10
//接口
public List<EMP> queryEMP(@Param("empnoList") List<Integer> empnoList);
//XML
<select id="queryEMP" parameterType="String" resultType="com.co.webapp.entity.EMP">
SELECT * FROM EMP WHERE EMPNO IN
<!-- collection:上面@Param()指定了入参名字,item:给collection值起的别名 -->
<foreach collection="empnoList" index="index" item="empno" open="(" separator="," close=")">
#{empno,mode=IN,jdbcType=VARCHAR}
</foreach>
</select>

批量插入

1
2
3
4
5
6
7
8
9
10
11
12
//接口
public void insertEMP(@Param("empList") List<EMP> empList);
//XML
<insert id="insertEMP" parameterType="java.util.List">
BEGIN
<foreach collection="empList" index="index" item="emp" separator=";" open="" close="">
INSERT INTO EMP(EMPNO, ENAME)
VALUES
(#{emp.empno,mode=IN,jdbcType=INTEGER},#{emp.ename,mode=IN,jdbcType=VARCHAR})
</foreach>
;END;
</insert>

choose

按顺序判断when中的条件是否成立,如果有一个成立则结束。当choose中所有when的条件都不满则时,则执行 otherwise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//接口
//如果对于入参是集合类型,且参数写了@Param("empMap"),则XML中入参需要加前缀,如:empMap.userId
public List<EMP> queryEMP(Map empMap);
//XML
<select id="queryEMP" parameterType="java.util.Map" resultType="com.co.webapp.entity.EMP">
SELECT * FROM EMP WHERE 1=1
<choose>
<when test="empno != null and empno != '' ">
AND EMPNO = #{empno,mode=IN,jdbcType=VARCHAR}
</when>
<otherwise>
AND ENAME = #{ename,mode=IN,jdbcType=VARCHAR}
</otherwise>
</choose>
</select>

where

如果where的标签中有返回值的话,就插入一个”where”

1
2
3
4
5
6
7
8
<select id="queryEMP" parameterType="java.util.Map" resultType="com.co.webapp.entity.EMP">
SELECT * FROM EMP
<where>
<if test="empno == -1">
AND 1 = 1
</if>
</where>
</select>

set

当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以自动添加SET 关键字,并且自动剔除追加到条件末尾的不需要用到的逗号

1
2
3
4
5
6
7
8
9
<update id="updateEMP" parameterType="com.co.webapp.entity.EMP">
UPDATE EMP
<set>
<if test="ename != null and ename != ''">
ENAME = #{ename,mode=IN,jdbcType=VARCHAR},
</if>
</set>
WHERE EMPNO = #{empno,mode=IN,jdbcType=INTEGER}
</update>

association、collection

两者适用场景:调用一次查询,将表A和表B关联查询出的结果集,分别放入实体A和实体B,允许二层及以上的嵌套查询
association:关联,一对一和多对一查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//EMP
Integer empno;
String ename;
Integer deptno;
DEPT deptEntity;

//DEPT
Integer deptno;
String dname;
String loc;

<resultMap id="EMP" type="com.co.webapp.entity.EMP">
<id column="EMPNO" property="empno" jdbcType="INTEGER"/>
<result column="ENAME" property="ename" jdbcType="VARCHAR"/>
<result column="DEPTNO" property="deptno" jdbcType="INTEGER"/>
<association property="deptEntity" javaType="com.co.webapp.entity.DEPT">
<id column="DEPTNO" property="deptno" jdbcType="INTEGER"/>
<result column="DNAME" property="dname" jdbcType="VARCHAR"/>
<result column="LOC" property="loc" jdbcType="VARCHAR"/>
</association>
</resultMap>

<select id="queryEMP" resultMap="EMP">
SELECT *
FROM Emp e
,Dept d
WHERE e.DEPTNO = d.DEPTNO
</select>

690858dcbd5f639940e1188bf2bcc5d3
collection:聚集,一对多查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//EMP
Integer empno;
String ename;
Integer deptno;
List<DEPT> deptEntityList;

//DEPT
Integer deptno;
String dname;
String loc;

<resultMap id="EMP" type="com.co.webapp.entity.EMP">
<id column="EMPNO" property="empno" jdbcType="INTEGER"/>
<result column="ENAME" property="ename" jdbcType="VARCHAR"/>
<result column="DEPTNO" property="deptno" jdbcType="INTEGER"/>
<collection property="deptEntityList" ofType="com.co.webapp.entity.DEPT">
<id column="DEPTNO" property="deptno" jdbcType="INTEGER"/>
<result column="DNAME" property="dname" jdbcType="VARCHAR"/>
<result column="LOC" property="loc" jdbcType="VARCHAR"/>
</collection>
</resultMap>

<select id="queryEMP" resultMap="EMP">
SELECT *
FROM Emp e
,Dept d
WHERE e.DEPTNO = d.DEPTNO
</select>

a46d8e57bdc101d7eed2b161c6d8ff68
额外:
这种方式用association或collection都可以,这种方式相当于两次查询,性能和效率较低

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//EMP
Integer empno;
String ename;
Integer deptno;
List<DEPT> deptEntityList;

//DEPT
Integer deptno;
String dname;
String loc;
<resultMap id="EMP" type="com.co.webapp.entity.EMP">
<id column="EMPNO" property="empno" jdbcType="INTEGER"/>
<result column="ENAME" property="ename" jdbcType="VARCHAR"/>
<result column="DEPTNO" property="deptno" jdbcType="INTEGER"/>
<!--column声明两个表是通过什么字段关联上的-->
<association column="DEPTNO" property="deptEntityList" select="queryDEPT"/>
</resultMap>
<select id="queryEMP" resultMap="EMP">
SELECT * FROM Emp e
</select>

<resultMap id="DEPT" type="com.co.webapp.entity.DEPT">
<id column="DEPTNO" property="deptno" jdbcType="INTEGER"/>
<result column="DNAME" property="dname" jdbcType="VARCHAR"/>
<result column="LOC" property="loc" jdbcType="VARCHAR"/>
</resultMap>
<select id="queryDEPT" parameterType="int" resultMap="DEPT">
SELECT * FROM Dept d WHERE DEPTNO = #{deptno}
</select>

调用存储过程

传入类型为Map,返回参数reCode和rtMessage会自动封装到map里面

1
2
3
4
5
6
7
8
9
10
//接口
public void callTest(Map empMap);
//XML
<select id="callTest" statementType="CALLABLE" parameterType="java.util.Map">
BEGIN
Apps.Test.Emp(x_Rt_Status => #{rtCode,mode=OUT,jdbcType=VARCHAR}
,x_Rt_Message => #{rtMessage,mode=OUT,jdbcType=VARCHAR}
,p_User_Id => #{userId,mode=IN,jdbcType=VARCHAR});
END;
</select>

e5384c634c92e66c7ff7abe82693585b
参数模式
STATEMENT(非预编译)、PREPARED(预编译)、CALLABLE。默认使用:PREPARED。
区别:

  • STATEMENT: 普通的不带参的查询SQL,支持批量更新,批量删除
  • PREPARED: 可变参数的SQL,编译一次多次执行,效率高,安全性好,有效防止Sql注入等问题,支持批量更新,批量删除
  • CALLABLE: 继承自PREPARED,支持带参数的SQL操作,支持调用存储过程,提供了对输入参数(IN)/输出参数(OUT)的支持,注:调用存储过程需用此方式