@Override
public void insertUser(User user){
Connection conn = DBUtil.getConnection();
PreparedStatement stmt = null;
String sql = "insert into sys_user(NAME,ACCT,PWD,CRTIME,UPTIME) values(?a,?c,?d,now(),now())";
try {
stmt = conn.prepareStatement(sql);
stmt.setString(1, user.getName());
stmt.setString(2, user.getAcct());
stmt.setString(3, user.getPwd());
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeAll(conn, stmt, null);
}
}
MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis,实质上MyBatis对iBatis进行一些改进
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建Connection、创建Statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
Mybatis通过xml或注解的方式将要执行的各种Statement(Statement、PreparedStatemnt、CallableStatement)配置起来,并通过java对象和Statement中的Sql进行映射生成最终执行的Sql语句,最后由MyBatis框架执行Sql并将结果映射成java对象并返回
MyBatis是一个持久层框架,操作数据库时使用的。无需创建JavaWEB项目,建立Java项目即可
maven依赖配置
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.38version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
作用:配置了数据源、事务等MyBatis运行环境等
<configuration>
<environments default="mysql">
<environment id="oracle">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="username" value="tom"/>
<property name="password" value="123456"/>
dataSource>
environment>
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
configuration>
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
//get,set方法省略...
}
<mapper namespace="emp">
<select id="findEmpById" parameterType="java.lang.Integer" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp where empno=#{abc}
select>
mapper>
在MyBatis中全局配置文件中添加映射文件位置
<mappers>
<mapper resource="com/mybatis/entity/Emp.xml"/>
mappers>
//1.创建读取全局配置文件的流
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//2.通过配置文件流创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.通过会话工厂创建会话对象(SqlSession)
SqlSession session = factory.openSession();
/*
4.通过会话对象操作数据库
selectOne(String statementId, Object param)查询单条数据
参数1:映射文件中的statementId,命名空间名.statementId
参数2:向sql语句中传入的数据,注意:传入的数据类型必须与映射文件中配置的parameterType保持一致
返回值:就是映射文件中配置的resultType的类型
*/
Emp emp = session.selectOne("emp.findEmpById",8001);
System.out.println(emp);
//5.关闭资源
session.close();
mapper文件:
<select id="findEmp" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp order by empno desc
select>
Java代码:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
List<Emp> list = session.selectList("emp.findEmp");
for (Emp e : list) {
System.out.println(e);
}
session.close();
mapper文件:
<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" >
insert into emp(empno,ename,job,mgr,hiredate,sal,comm)
values(#{empno},#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm})
insert>
Java代码:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
Emp emp = new Emp();
emp.setEname("tom");
emp.setJob("clrek");
emp.setMgr(1);
emp.setHiredate(new Date());
emp.setSal(6500.0);
emp.setComm(1200.0);
//在mybaits中事务默认需要手动提交
int result = session.insert("emp.insertEmp",emp);
System.out.println(result);
//执行提交的方法
session.commit();
session.close();
插入数据的主键返回:
<selectKey resultType="java.lang.Integer" keyProperty="empno" order="AFTER">
select last_insert_id()
selectKey>
<selectKey resultType="java.lang.Integer" keyProperty="empno" order="BEFORE">
select seq_demo.nextval from dual
selectKey>
如果是主键自增型数据库还可以使用:
<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" keyProperty="empno" useGeneratedKeys="true">
mapper文件:
<update id="updateEmp" parameterType="com.mybatis.entity.Emp">
update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm}
where empno=#{empno}
update>
Java代码:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
Emp emp = new Emp();
emp.setEmpno(52);
emp.setEname("jerry");
emp.setJob("manager");
emp.setMgr(10);
emp.setHiredate(new Date());
emp.setSal(8500.0);
emp.setComm(1200.0);
int result = session.update("emp.updateEmp",emp);
System.out.println(result);
//执行提交的方法
session.commit();
session.close();
mapper文件:
<delete id="deleteEmp" parameterType="java.lang.Integer">
delete from emp where empno=#{empno}
delete>
Java代码:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
int result = session.delete("emp.deleteEmp",8000);
System.out.println(result);
//执行提交的方法
session.commit();
session.close();
mapper文件:
<select id="findEmpByEname" parameterType="java.lang.String" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where ename like #{abc}
select>
<select id="findEmpByEname2" parameterType="java.lang.String" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where ename like '%${value}%'
select>
Java代码:
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
List<Emp> list = session.selectList("emp.findEmpByEname", "%tom%");
//List list = session.selectList("emp.findEmpByEname", "tom");
for (Emp e : list) {
System.out.println(e);
}
session.close();
#{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型、pojo、HashMap
#{}接收简单类型,#{}中可以写成value或其它名称
#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值
${}表示一个拼接符号,会引用Sql注入,所以不建议使用${}
${}接收输入参数,类型可以是简单类型、pojo、HashMap
${}接收简单类型,${}中只能写成value
${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值
SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory
SqlSession是一个面向用户(程序员)的接口,其中提供了很多操作数据库的方法。如:selectOne(返回单个对象)、selectList(返回单个或多个对象)、insert、update、delete。
SqlSession的实例不能共享使用,它是线程不安全的,每个线程都应该有它自己的SqlSession实例,因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
为了简化MyBatis的开发,可将MyBatis进一步封装
public class MybatisUtil {
/**
* 不让用户在外界创建工具类对象
*/
private MybatisUtil(){}
/**
* 初始化工厂
*/
private static SqlSessionFactory factory;
static {
try {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象的方法
*/
public static SqlSession openSession(){
return factory.openSession();
}
}
原始Dao开发方法需要程序员编写Dao接口和Dao实现类
接口:
public interface DeptDao {
public List<Dept> findDept();
public Dept findDeptById(Integer deptno);
public void insertDept(Dept dept);
public void updateDept(Dept dept);
public void deleteDept(Integer deptno);
}
实现类:
public class DeptDaoImpl implements DeptDao {
@Override
public List<Dept> findDept() {
SqlSession session = MybatisUtil.openSession();
List<Dept> list = session.selectList("dept.findDept");
session.close();
return list;
}
@Override
public Dept findDeptById(Integer deptno) {
SqlSession session = MybatisUtil.openSession();
Dept dept = session.selectOne("dept.findDeptById",deptno);
session.close();
return dept;
}
@Override
public void insertDept(Dept dept) {
SqlSession session = MybatisUtil.openSession();
session.insert("dept.insertDept",dept);
session.commit();
session.close();
}
@Override
public void updateDept(Dept dept) {
SqlSession session = MybatisUtil.openSession();
session.update("dept.updateDept",dept);
session.commit();
session.close();
}
@Override
public void deleteDept(Integer deptno) {
SqlSession session = MybatisUtil.openSession();
session.delete("dept.deleteDept",deptno);
session.commit();
session.close();
}
}
原始DAO开发问题
Mapper代理开发方式只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法
程序员编写Mapper接口需要遵循一些开发规范,MyBatis可以自动生成Mapper接口实现类代理对象
开发规范:
Mapper接口:
public interface EmpMapper {
public List<Emp> findEmp();
public Emp findEmpByEmpno(Integer empno);
/**
* 增删改方法的返回值
* 1.void 无返回值
* 2.int 返回操作数据库表的记录数
* 3.boolean 根据返回数据库表影响的记录数,来判断是否成功
* 注意:影响的记录数大于等于1,返回值为true,否则为false
*/
public void insertEmp(Emp emp);
public void updateEmp(Emp emp);
public void deleteEmp(Integer empno);
}
映射文件:
<mapper namespace="com.mybatis.mapper.EmpMapper">
<select id="findEmpByEmpno" parameterType="java.lang.Integer" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp where empno=#{abc}
select>
<select id="findEmp" resultType="com.mybatis.entity.Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp order by empno desc
select>
<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" >
insert into emp(ename,job,mgr,hiredate,sal,comm)
values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm})
insert>
<update id="updateEmp" parameterType="com.mybatis.entity.Emp">
update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},
sal=#{sal},comm=#{comm} where empno=#{empno}
update>
<delete id="deleteEmp" parameterType="java.lang.Integer">
delete from emp where empno=#{empno}
delete>
mapper>
测试:
SqlSession session = MybatisUtil.openSession();
//通过SqlSession对象获得到你指定Mapper接口的代理对象(就是接口的实现类对象)
EmpMapper mapper = session.getMapper(EmpMapper.class);
MyBatis的全局配置文件mybatis-config.xml,配置内容如下:
将数据库连接参数单独配置在db.properties中,只需要在mybatis-config.xml中加载db.properties的属性值。在mybatis-config.xml中就不需要对数据库连接参数硬编码
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis
mysql.username=root
mysql.password=123456
在mybatis-config.xml加载属性文件:
<properties resource="db.properties">
properties>
注意: MyBatis将按照下面的顺序来加载属性:
建议:
MyBatis框架在运行时可以调整一些运行参数
比如:开启二级缓存、开启延迟加载
可配置参数如下:
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发
别名 | 映射的类型 | 别名 | 映射的类型 |
---|---|---|---|
_byte | byte | byte | java.lang.Byte |
_short | short | short | java.lang.Short |
_int | int | int | java.lang.Integer |
_integer | int | integer | java.lang.Integer |
_long | long | long | java.lang.Long |
_float | float | float | java.lang.Float |
_double | double | double | java.lang.Double |
_boolean | boolean | boolean | java.lang.Boolean |
string | java.lang.String | date | java.util.Date |
map | java.util.Map | hashmap | java.util.HashMap |
list | java.util.List | arraylist | java.util.ArrayList |
object | java.lang.Object |
单个定义别名:
<typeAliases>
<typeAlias type="com.mybatis.entity.Dept" alias="abc"/>
typeAliases>
<select id="findDeptById" parameterType="int" resultType="abc">
select deptno,dname,loc from dept where deptno=#{deptno}
select>
批量定义别名:
<typeAliases>
<package name="com.mybatis.entity"/>
typeAliases>
MyBatis中通过typeHandlers完成jdbc类型和Java类型的转换,MyBatis自带的类型处理器基本上满足日常需求,不需要单独定义
MyBatis支持类型处理器:
类型处理器 | Java类型 | JDBC类型 |
---|---|---|
BooleanTypeHandler | Boolean,boolean | 任何兼容的布尔值 |
ByteTypeHandler | Byte,byte | 任何兼容的数字或字节类型 |
ShortTypeHandler | Short,short | 任何兼容的数字或短整型 |
IntegerTypeHandler | Integer,int | 任何兼容的数字和整型 |
LongTypeHandler | Long,long | 任何兼容的数字或长整型 |
FloatTypeHandler | Float,float | 任何兼容的数字或单精度浮点型 |
DoubleTypeHandler | Double,double | 任何兼容的数字或双精度浮点型 |
BigDecimalTypeHandler | BigDecimal | 任何兼容的数字或十进制小数类型 |
StringTypeHandler | String | CHAR和VARCHAR类型 |
ClobTypeHandler | String | CLOB和LONGVARCHAR类型 |
NStringTypeHandler | String | NVARCHAR和NCHAR类型 |
NClobTypeHandler | String | NCLOB类型 |
ByteArrayTypeHandler | byte[] | 任何兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB和LONGVARBINARY类型 |
DateTypeHandler | java.util.Date | TIMESTAMP类型 |
DateOnlyTypeHandler | java.util.Date | DATE类型 |
TimeOnlyTypeHandler | java.util.Date | TIME类型 |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP类型 |
SqlDateTypeHandler | java.sql.Date | DATE类型 |
SqlTimeTypeHandler | java.sql.Time | TIME类型 |
ObjectTypeHandler | 任意 | 其他或未指定类型 |
EnumTypeHandler | Enumeration类型 | VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引) |
通过resource加载单个映射文件
<mappers>
<mapper resource="com/mybatis/mapper/DeptMapper.xml"/>
<mapper resource="com/mybatis/mapper/EmpMapper.xml"/>
mappers>
通过mapper接口加载单个映射文件
<mappers>
<mapper class="com.mybatis.mapper.DeptMapper"/>
<mapper class="com.mybatis.mapper.EmpMapper"/>
mappers>
指定Mapper接口的包名,MyBatis自动扫描包下边所有Mapper接口进行加载
遵循规范:与mapper接口加载单个映射文件一致
<mappers>
<package name="com.mybatis.mapper"/>
mappers>
mapper.xml映射文件中定义了操作数据库的Sql,每个Sql是一个statement,映射文件是MyBatis的核心
<select id="findUsersByRealname" parameterType="string" resultType="Users">
select userid,username,password,realname from users where realname like #{realname}
select>
开发中通过实体类或pojo类型传递查询条件,查询条件是综合的查询条件,不仅包括实体类中查询条件还包括其它的查询条件,这时可以使用包装对象传递输入参数
实体类:Users和Pagebean
//实体类
public class Users{
private Integer userid;
private String username;
private String password;
private String realname;
//get,set方法省略...
}
//页时使用的pojo对象
public class Pagebean {
private int page;
private int pageSize;
private int maxCount;
private int maxPage;
private int offset;
//get,set方法省略...
}
复合实体类:UsersQuery
public class UsersQuery {
private Users users;
private Pagebean pagebean;
//get,set方法省略...
}
映射文件:
<select id="findUsersByRealnameAndPage" parameterType="UsersQuery" resultType="Users">
select
userid,username,password,realname from users
where
realname like #{users.realname}
order by userid
limit #{pagebean.offset},#{pagebean.pageSize}
select>
<select id="findUsersWithMap" parameterType="map" resultType="Users">
select
userid,username,password,realname from users
where
realname like #{map_realname}
order by userid
limit #{map_offset},#{map_size}
select>
MyBatis中允许有多个输入参数,可使用@Param注解来表示
/**
* @Param注解可以实现多个输入参数
* 每个输入参数前必须使用@Param注解
* 注解中value属性的值为获取此参数值的key
*
* 多参数使用了注解之后,mybatis就将这些注解中value属性值与参数值存放一个map集合中
* 其中value属性值为map集合的key
* 参数值为map集合value
*
* 使用此种方法可以省略paramterType的配置
*/
public Users login(@Param(value = "uname") String username, @Param("pwd") String password);
这种做法类似与Map类型的输入参数,其中@Param注解的value属性值为Map的key,在映射文件中通过ognl可获取对应的value,并且parameterType可以不指定类型
<select id="login" resultType="Users">
select userid,username,password,realname from users
where username=#{uname} and password=#{pwd}
select>
查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射
public int findUsersCount();
<select id="findUsersCount" resultType="int">
select count(*) from users
select>
不管是输出的实体类是单个对象还是一个列表(list中包括实体类对象),在mapper.xml中resultType指定的类型是一样的
在原始Dao的方式中,通过selectOne和selectList方法来区分返回值为单个对象或集合列表,而在mapper代理中,则通过接口中定义的方法返回值来区分
public Users findUsersByUserid(Integer userid);
public List<Users> findUsers();
<select id="findUsersByUserid" parameterType="int" resultType="Users">
select userid,username,password,realname from users where userid=#{userid}
select>
<select id="findUsers" resultType="Users">
select userid,username,password,realname from users order by userid
select>
定义resultMap
<resultMap id="usersResultMap" type="Users">
<id property="userid" column="id"/>
<result property="username" column="uname"/>
<result property="password" column="pwd"/>
<result property="realname" column="rname"/>
resultMap>
使用resultMap作为statement的输出映射类型
<select id="findUsersWithResultMap" resultMap="usersResultMap">
select userid id,username uname,password pwd,realname rname from users
select>
动态Sql是指MyBatis核心对Sql语句进行灵活操作,通过表达式进行判断,对Sql进行灵活拼接、组装
将实体类不为空的属性作为where条件
<select id="findEmpUseIf" parameterType="map" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where 1=1
<if test="ename!=null and ename!=''">
and ename like #{ename}
if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
if>
<if test="deptno!=null and deptno!=0">
and deptno=#{deptno}
if>
select>
where标签中包含的任意if条件如果成立,它就插入一个where关键字。此外,如果标签返回的内容是以AND 或OR 开头的,则它会自动剔除掉
<select id="findEmpUseWhere" parameterType="map" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
<where>
<if test="ename!=null and ename!=''">
and ename like #{ename}
if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
if>
<if test="deptno!=null and deptno!=0">
and deptno=#{deptno}
if>
where>
select>
当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置SET关键字,和剔除追加到条件末尾的任何不相关的逗号
注意:如果set包含的内容为空的话则会出错
<update id="updateEmpUseSet" parameterType="Emp">
update emp
<set>
<if test="ename!=null">
ename=#{ename},
if>
<if test="job!=null">
job=#{job},
if>
<if test="mgr!=null">
mgr=#{mgr},
if>
<if test="sal!=null">
sal=#{sal},
if>
<if test="comm!=null">
comm=#{comm},
if>
<if test="hiredate!=null">
hiredate=#{hiredate},
if>
set>
where empno=#{empno}
update>
trim标签属性解析:
trim来代替where标签的功能
<select id="findEmpUseTrim" parameterType="Emp" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
<trim prefix="where" prefixOverrides="and|or">
<if test="ename!=null">
and ename like #{ename}
if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
if>
<if test="job!=null">
and job=#{job}
if>
trim>
select>
trim来代替set标签的功能
<update id="updateEmpUseTrim" parameterType="Emp">
update emp
<trim prefix="set" suffixOverrides=",">
<if test="ename!=null">
ename=#{ename},
if>
<if test="job!=null">
job=#{job},
if>
<if test="mgr!=null">
mgr=#{mgr},
if>
<if test="sal!=null">
sal=#{sal},
if>
<if test="comm!=null">
comm=#{comm},
if>
<if test="hiredate!=null">
hiredate=#{hiredate},
if>
trim>
where empno=#{empno}
update>
trim实现insert语句
<insert id="insertEmpUseTrim" parameterType="Emp">
insert into emp
<trim suffix="(" prefix=")" prefixOverrides=",">
<if test="ename!=null">
ename,
if>
<if test="job!=null">
job,
if>
<if test="mgr!=null">
mgr,
if>
<if test="hiredate!=null">
hiredate,
if>
<if test="sal!=null">
sal,
if>
<if test="comm!=null">
comm,
if>
trim>
<trim prefix=" values(" suffix=")" suffixOverrides=",">
<if test="ename!=null">
#{ename},
if>
<if test="job!=null">
#{job},
if>
<if test="mgr!=null">
#{mgr},
if>
<if test="hiredate!=null">
#{hiredate},
if>
<if test="sal!=null">
#{sal},
if>
<if test="comm!=null">
#{comm},
if>
trim>
insert>
属性解析:
public void deleteEmpUseForeachArray(int[] empnos);
public List<Emp> findEmpUseForeachList(List<Integer> empnos);
public List<Emp> findEmpUseForeachPojo(EmpQuery query);
<delete id="deleteEmpUseForeachArray" parameterType="int">
delete from emp where empno in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
foreach>
delete>
<select id="findEmpUseForeachList" parameterType="int" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where empno in
<foreach collection="list" open="(" close=")" separator="," item="empno">
#{empno}
foreach>
select>
<select id="findEmpUseForeachPojo" parameterType="EmpQuery" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where deptno in
<foreach collection="deptnos" open="(" close=")" separator="," item="deptno">
#{deptno}
foreach>
select>
if-else-if判断
<select id="">
select...
<choose>
<when test="">
when>
<when test="">
when>
<otherwise>
otherwise>
choose>
select>
将实现的动态Sql判断代码块抽取出来,组成一个Sql片段,其它的statement中就可以引用Sql片段,方便程序员进行开发
注意:在sql片段中不要包括where标签
<select id="findEmpUseSql" parameterType="map" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
<where>
<include refid="empSql"/>
where>
select>
<sql id="empSql">
<if test="ename!=null">
and ename like #{ename}
if>
<if test="sal!=null and sal!=0.0">
and sal=#{sal}
if>
<if test="deptno!=null and deptno!=0">
and deptno=#{deptno}
if>
sql>
表功能介绍
表与表之间的业务关系
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
public class Users {
private Integer userid;
private String username;
private String password;
private String realname;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
//get,set方法省略...
}
原始的Orders类不能映射全部字段,需要新创建的实体类,创建一个包括查询字段较多的实体类
OrdersUsers中包含了Orders以及Users需要查询的属性
public class OrdersUsers {
/**
* 对应orders表中的字段
*/
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 对象users表中的字段
*/
private Integer userid;
private String username;
private String password;
private String realname;
}
public List<OrdersUsers> findOrdersUseResultType();
<select id="findOrdersUseResultType" resultType="OrdersUsers">
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
select>
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<OrdersUsers> list = mapper.findOrdersUseResultType();
for (OrdersUsers ou : list) {
System.out.println(ou);
}
session.close();
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
在Orders类中加入Users属性,Users属性用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个Users对象存储关联查询的用户信息
public class Users {
private Integer userid;
private String username;
private String password;
private String realname;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 一对一/多对一依赖关系属性
*/
private Users users;
//get,set方法省略...
}
public List<Orders> findOrdersUseResultMap();
<resultMap id="ordersUsersResultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
<association property="users" javaType="Users">
<id column="userid" property="userid"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="realname" property="realname"/>
association>
resultMap>
<select id="findOrdersUseResultMap" resultMap="ordersUsersResultMap">
SELECT
id, order_number,totalprice,status,u.userid,username,password,realname
FROM
orders o,users u
WHERE
o.userid=u.userid
select>
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersUseResultMap();
for (Orders o : list) {
System.out.println(o);
}
session.close();
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id
FROM
orders o,ordersdetail d
WHERE
o.id=d.orders_id
在Order类中加入List details属性,details属性用于存储关联查询的订单详情,因为订单关联查询订单详情是一对多关系,所以这里使用集合对象存储关联查询的订单详情信息
public class OrdersDetail {
private Integer id;
private Integer amount;
private Integer goods_id;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 一对多,多对多依赖关系属性
*/
private List<OrdersDetail> details;
//get,set方法省略...
}
public List<Orders> findOrdersAndOrdersDetail();
<resultMap id="ordersAndDetailResultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
<collection property="details" ofType="OrdersDetail">
<id column="detailid" property="id"/>
<result column="amount" property="amount"/>
<result column="goods_id" property="goods_id"/>
collection>
resultMap>
<select id="findOrdersAndOrdersDetail" resultMap="ordersAndDetailResultMap">
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id
FROM
orders o,ordersdetail d
WHERE
o.id=d.orders_id
select>
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersAndOrdersDetail();
for (Orders orders : list) {
System.out.println(orders);
}
session.close();
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id,gname,descr,price
FROM
orders o,ordersdetail d,goods g
WHERE
o.id=d.orders_id
AND
d.goods_id=g.id
将Orderdetail类中Integer goods_id属性修改为Goods goods属性,goods属性用于存储关联查询的商品信息。订单与订单详情是一对多关系,订单详情与商品是一对一关系,反之商品与订单详情是一对多关系,订单详情与订单是一对一关系,所以订单与商品之前为多对多关系
public class Goods {
private Integer id;
private String gname;
private String descr;
private Double price;
//get,set方法省略...
}
public class OrdersDetail {
private Integer id;
private Integer amount;
/**
* 一对一依赖关系属性
*/
private Goods goods;
//get,set方法省略...
}
public class Orders {
private Integer id;
private String order_number;
private Double totalPrice;
private String status;
/**
* 一对多,多对多依赖关系属性
*/
private List<OrdersDetail> details;
//get,set方法省略...
}
public List<Orders> findOrdersAndGoods();
<resultMap id="ordersAndGoodsResultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
<collection property="details" ofType="OrdersDetail">
<id column="detailid" property="id"/>
<result column="amount" property="amount"/>
<association property="goods" javaType="Goods">
<id column="goods_id" property="id"/>
<result column="gname" property="gname"/>
<result column="descr" property="descr"/>
<result column="price" property="price"/>
association>
collection>
resultMap>
<select id="findOrdersAndGoods" resultMap="ordersAndGoodsResultMap">
SELECT
o.id,order_number,totalprice,status,d.id detailid,amount,goods_id,gname,descr,price
FROM
orders o,ordersdetail d,goods g
WHERE
o.id=d.orders_id
AND
d.goods_id=g.id
select>
SqlSession session = MybatisUtil.openSession();
OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersAndGoods();
for (Orders orders : list) {
System.out.println(orders);
}
session.close();
SELECT
s.id,name,gender,major,course_id,cname
FROM
student s,student_course sc,course c
WHERE
s.id=sc.student_id
AND
sc.course_id=c.id
public class Course {
private Integer id;
private String cname;
//get,set方法省略...
}
public class Student {
private Integer id;
private String name;
private String gender;
private String major;
/**
* 多对多的依赖关系属性
*/
private List<Course> courses;
//get,set方法省略...
}
public List<Student> findStudent();
<resultMap id="studentAndCourseResultMap" type="Student">
<id column="id" property="id"/>
<result column="NAME" property="name"/>
<result column="gender" property="gender"/>
<result column="major" property="major"/>
<collection property="courses" ofType="Course">
<id column="course_id" property="id"/>
<result column="cname" property="cname"/>
collection>
resultMap>
<select id="findStudent" resultMap="studentAndCourseResultMap">
SELECT
s.id,name,gender,major,course_id,cname
FROM
student s,student_course sc,course c
WHERE
s.id=sc.student_id
AND
sc.course_id=c.id
select>
SqlSession session = MybatisUtil.openSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.findStudent();
for (Student student : list) {
System.out.println(student);
}
session.close();
作用:将查询结果按照Sql列名与实体类属性名一致性映射到实体类对象中
场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到实体类中,在前端页面遍历list(list中是实体类)即可
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)
作用:将关联查询信息映射到一个实体类对象中
场合:为了方便查询关联信息可以使用association将关联信息映射为当前对象的一个属性,比如:查询订单以及关联用户信息
作用:将关联查询信息映射到一个list集合中
场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。如果使用resultType无法将查询结果映射到list集合中
resultMap标签可以通过extends属性来继承一个已有的或公共的resultMap,避免重复配置的出现,减少配置量。例子如下:
<resultMap id="ordersRusultMap" type="Orders">
<id column="id" property="id"/>
<result column="order_number" property="order_number"/>
<result column="totalprice" property="totalPrice"/>
<result column="status" property="status"/>
resultMap>
<resultMap id="ordersUsersResultMap" type="Orders" extends="ordersRusultMap">
<association property="users" javaType="Users">
<id column="userid" property="userid"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="realname" property="realname"/>
association>
resultMap>
在MyBatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading
设置项 | 描述 | 允许值 | 默认值 |
---|---|---|---|
lazyLoadingEnabled | 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载 | true \ false | false |
aggressiveLazyLoading | 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载 | true \ false | true |
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
查询员工以及相关联的部门信息
public List<Emp> findEmp();
查询员工信息
<select id="findEmp" resultMap="empResultMap">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
select>
查询关联的部门信息
通过上边查询到的员工信息中deptno外键去关联查询部门信息,所以需要定义一个根据ID查询部门的语句
<select id="findDeptByDeptno" parameterType="int" resultType="Dept">
select deptno,dname,loc from dept where deptno=#{deptno}
select>
resultMap配置
<resultMap id="empResultMap" type="Emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<association property="dept" javaType="Dept" select="com.mybatis.mapper.DeptMapper.findDeptByDeptno" column="deptno">
association>
resultMap>
public List<Dept> findDept();
查询部门信息
<select id="findDept" resultMap="deptResultMap">
select deptno,dname,loc from dept
select>
查询关联的员工详情信息
通过查询到的部门信息中deptno去关联查询员工详情,所以需要定义一个根据部门ID查询员工详情的语句
<select id="findEmpByDeptno" parameterType="int" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm from emp
where deptno=#{deptno}
select>
resultMap配置
<resultMap id="deptResultMap" type="Dept">
<id column="deptno" property="deptno"/>
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
<collection property="empList" ofType="Emp" select="com.mybatis.mapper.EmpMapper.findEmpByDeptno" column="deptno"/>
resultMap>