一、resultMap标签的使用
1.解决列名和属性名的不一致:
如果查询时使用 resultType 属性, 表示采用 MyBatis 的Auto-Mapping(自动映射)机制, 即相同的列名和属性名会自动匹配. 因此, 当数据库表的列名和类的属性名不一致时, 会导致查不到数据. 解决该问题可以有两种方式:
-
起列别名:
查询时, 可以通过列别名的方式将列名和属性名保持一致, 继续使用自动映射, 从而解决该问题. 但是较为麻烦。
<select id="selAll" resultType="user">
select id id1, username username1, password password2 from t_user
</select>
-
使用<resultMap>标签
<resultMap>用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系。一旦使用 resultMap, 表示不再采用自动映射机制。
(1)代码示例:
<mapper namespace="com.zlw.mapper.UserMapper">
<resultMap type="user" id="umap">
<id column="userId" property="userId1"/>
<result column="userName" property="userName1"/>
<result column="userPass" property="userpass1"/>
</resultMap>
<select id="selAll" resultMap="umap">
select* from t_user
</select>
</mapper>
(2)测试:
@Test
public void Sel() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
List<User> list = session.selectList("com.zlw.mapper.UserMapper.selAll");
for (User user : list) {
System.out.println(user);
}
session.close();
}
(3)结果:
结果
2.多表连接查询(多对一):
mapper 层只做单表查询操作, 在 service 层进行手动装配, 实现关联查询的结果。
创建两个表;
创建两个实体类;
Mapper层:
提供StudentMapper和ClazzMapper, StudentMapper查询所有学生信息,ClazzMapper 根据编号查询班级信息。
(1)sql语句:
create table t_class(
id int(3) PRIMARY key auto_increment,
name VARCHAR(20) not null,
room VARCHAR(20)
)
create table t_student(
id int(5) PRIMARY KEY auto_increment,
name VARCHAR(30) not null,
age int(3),
gender CHAR(3),
cid int(3) references t_class (id)
)
(2)映射文件配置:
<select id="selAll" resultType="Student">
select *from t_student
</select>
<mapper namespace="com.zlw.mapper.ClazzMapper">
<select id="findById" resultType="clazz" parameterType="int">
select *from t_class where id = #{0}
</select>
</mapper>
(3)Service层:
public List<Student> selAll() {
//学生mapper
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper stumapper= session.getMapper(StudentMapper.class);
//班级mapper
ClazzMapper clamapper = session.getMapper(ClazzMapper.class);
List<Student> list = stumapper.selAll();
for (Student student : list) {
int id = student.getCid();
Clazz clazz = clamapper.findById(id);
student.setClazz(clazz);
}
session.close();
return list;
}
(4)测试:
@Test
public void StudentTest() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll();
for (Student student : list) {
System.out.println(student);
}
}
结果
3.resultMap的N+1方式实现多表查询(多对 一)
<association>标签的使用;用于关联一个对象 。
属性:
property: 指定要关联的属性名 ;
select: 设定要继续引用的查询, namespace+id ;
column: 查询时需要传递的列 ;
(1)mapper层:
提供StudentMapper和ClazzMapper, StudentMapper查询所有学生信息,ClazzMapper 根据编号查询班级信息。再StudentMapper 中使用<association>设置装配。
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<resultMap type="student" id="smap">
<!-- N+1查询时, 同名映射可以省略, 但是只能使用一次 -->
<result property="cid" column="cid" />
<!-- 用于关联一个对象 -->
<association property="clazz" select="com.zlw.mapper.ClazzMapper.selById"
column="cid">
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select * from t_student
</select>
</mapper>
<mapper namespace="com.zlw.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id=#{0}
</select>
</mapper>
(2)service层:
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
// 学生mapper
StudentMapper stuMapper = session.getMapper(StudentMapper.class);
List<Student> list = stuMapper.selAll();
session.close(); return list;
}
(3)测试:
@Test
public void StudentTest() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll();
for (Student student : list) {
System.out.println(student);
}
}
结果
4.解决N+1问题:
使用多表表连接查询语句;
在 StudentMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应班级的信息。
通过<resultMap>定义映射关系, 并通过<association>指定对象属性的映射关系. 可以把<association>看成一个<resultMap>使用. javaType 属性表示当前对象, 可以写全限定路径或别名。
(1)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>
<properties resource="db.properties" />
<settings>
<setting name="logImpl" value="LOG4J" />
</settings>
<typeAliases>
<package name="com.zlw.pojo"/>
</typeAliases>
<environments default="dev1">
<environment id="dev1">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="pooled">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.zlw.mapper"/>
</mappers>
</configuration>
(2)封装简单的工具类:
package com.zlw.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
static {
try {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
SqlSession session = null;
if (factory != null) {
session = factory.openSession();
}
return session;
}
}
(3)mapper层:
<resultMap type="student" id="umap">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
<association property="clazz" javaType="clazz">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
</association>
</resultMap>
<select id="selAll2" resultMap="umap">
select s.*,c.name cname ,c.room from t_student s
LEFT JOIN t_class c on s.cid= c.id
</select>
<mapper namespace="com.zlw.mapper.ClazzMapper">
<select id="findById" resultType="clazz" parameterType="int">
select *from t_class where id = #{0}
</select>
</mapper>
(4)service层:
public List<Student> selAll2() {
//学生mapper
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper stumapper= session.getMapper(StudentMapper.class);
List<Student> list = stumapper.selAll2();
session.close();
return list;
}
(5)测试:
@Test
public void StudentTest2() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll2();
for (Student student : list) {
System.out.println(student);
}
}
结果
5.resultMap的关联方式实现多表查询(一对多) :
在 ClazzMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应学生的信息。
通过<resultMap>定义映射关系, 并通过<collection>指定集合属性泛型的映射关系. 可以把<collection>看成一个<resultMap>使用。ofType 属性表示集合的泛型, 可以写全限定路径或别名。
- mapper层:
<resultMap type="clazz" id="cmap2">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="room" column="room"/>
<collection property="stus" javaType="list" ofType="student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="cid" column="cid"/>
</collection>
</resultMap>
<select id="selAll2" resultMap="cmap2">
select c.*,s.id sid,s.name sname ,s.age,s.gender,s.cid from t_student s
right JOIN t_class c on s.cid= c.id
</select>
<mapper namespace="com.zlw.mapper.StudentMapper">
<select id="findById" resultType="student">
select *from t_student where cid = #{0}
</select>
</mapper>
- service层:
public List<Clazz> selAll2() {
SqlSession session = MyBatisUtil.getSqlSession();
ClazzMapper mapper = session.getMapper(ClazzMapper.class);
List<Clazz> list = mapper.selAll2();
return list;
}
(3)测试:
@Test
public void ClazzTest2() {
ClassService cs = new ClazzServiceImpl();
List<Clazz> list = cs.selAll2();
for (Clazz clazz : list) {
System.out.println(clazz);
}
}
结果
6.通过Auto-Mapping实现多表查询 :
) 通过 MyBatis 的 Auto-Mapping 机制及数据库查询时的别
名结合, 可以方便的实现多表查询。
SQL 语句中, 别名出现特殊符号时, 必须进行处理. MySQL可以使用(``)符号, Oracle 可以使用("")符号。
(1)mapper:
<!-- auto -->
<select id="selAll3" resultType="student">
select s.*,c.id `clazz.id`,c.name `clazz.name` ,c.room `clazz.room`
from t_student s
LEFT JOIN t_class c
on s.cid= c.id
</select>
(2)service:
public List<Student> selAll3() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.selAll3();
session.close();
return list;
}
(3)测试:
@Test
public void StudentTest3() {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll3();
for (Student student : list) {
System.out.println(student);
}
}
结果
二、MyBatis的注解开发
1.注解开发:
注解是用于描述代码的代码. 例如: @Test(用于描述方法进行 junit 测试),@Override(用于描述方法的重写), @Param(用于描述属性的名称)。
使用前必须先导包 ;
使用注解一般用于简化配置文件. 但是, 注解有时候也不是很友好(有时候反而更麻烦), 例如动态 SQL。
注解和配置文件可以配合使用。
-
注解的属性:
属性的设定方式是: 属性名=属性值 ;
基本类型和 String, 可以直接使用双引号的形式
数组类型, name={值 1, 值 2, ...}; 如果数组元素只有一个, 可以省略大括号;
对象类型, name=@对象名(属性) 。
如果属性是该注解的默认属性, 而且该注解只配置这一个属性, 可以将属性名省略。
2.使用注解完成单表增删改查:
@Select: 类似于<select>
@Insert: 类似于<insert>
@Update: 类似于<update>
@Delete: 类似于<delete>
(1)mapper:
package com.zlw.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.zlw.pojo.Student;
public interface StudentMapper {
@Select("select * from t_student")
List<Student> sleAll();
@Insert("insert into t_student values(default,#{name},#{age},#{gender},#{cid})")
int add(Student stu);
@Update("update t_student set age=#{1} where id=#{0}")
int update(int id, int age);
@Delete("delete from t_student where id = #{0}")
int delete(int id);
}
(2)测试:
package com.zlw.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.zlw.mapper.StudentMapper;
import com.zlw.pojo.Student;
import com.zlw.util.MyBatisUtil;
public class Test01 {
@Test
public void selAll() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.sleAll();
for (Student student : list) {
System.out.println(student);
}
session.close();
}
@Test
public void add() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student stu = new Student();
stu.setName("Dave");
stu.setAge(18);
stu.setGender("男");
stu.setCid(2);
int num = mapper.add(stu);
if(num>0) {
System.out.println("添加成功!");
session.commit();
}else {
System.out.println("添加失败!");
session.rollback();
}
session.close();
}
@Test
public void update() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
int num = mapper.update(6,20);
if(num>0) {
System.out.println("修改成功!");
session.commit();
}else {
System.out.println("修改失败!");
session.rollback();
}
session.close();
}
@Test
public void delete() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
int num = mapper.delete(6);
if(num>0) {
System.out.println("删除成功!");
session.commit();
}else {
System.out.println("删除失败!");
session.rollback();
}
session.close();
}
}
3.其他注释:
@Results: 类似于<resultMap>
@Result: 类似于<resultMap>的子标签
@One: 类似于<association>
@Many: 类似于<collection>
- 实现多表查询操作:
(1)mapper:
public interface StudentMapper {
@Select("select *from t_student")
@Results(value= {
@Result(column="id",property = "id", id=true),
@Result(column = "name",property = "name"),
@Result(column = "age",property = "age"),
@Result(column = "gender",property = "gender"),
@Result(column = "cid",property = "cid"),
@Result(column = "cid",property = "clazz",one =@One(select= "com.zlw.mapper.ClazzMapper.selAll"))
})
List<Student> selAll();
}
public interface ClazzMapper {
@Select("select *from t_class where id = #{0}")
Clazz selAll(int id);
}
(2)测试:
@Test
public void selAll() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentMapper mapper= session.getMapper(StudentMapper.class);
List<Student> list = mapper.selAll();
for (Student student : list) {
System.out.println(student);
}
}
结果
三、MyBatis的运行原理
1.MyBatis中涉及的接口和类:
- 类:
(1)Resources:用于加载MyBatis核心配置文件;
(2)XMLConfigBuilder:用于解析xml文件;
(3)Configuration:用于存放xml文件解析后的结果;
(4)DefaultSqlSessionFactory:是 SqlSessionFactory接口的实现类,创建时需要使用Configuration 对象;
(5)DefaultSqlSession:是 SqlSession 接口的实现类;
- 接口:
(1)SqlSession:是MyBatis操作的核心;
(2)TransactionFactory:用于生产Transaction对象;
(3)Transaction:用于表示操作数据库的事务对象;
(4)Executor:是MyBatis的核心执行器,类似于jdbc中的Statement,常用的实现类是SimpleExecutor。
2.MyBatis的运行原理:
当MyBatis运行开始时,先通过Resource加载核心配置文件,再使用XMLConfigBuilder对配置文件进行解析,将解析结果封装为Configuration对象, 然后, 使用Configuration对象构建一个DefaultSqlSessionFactory对象, 至此, SqlSession工厂构建完成。
接下来, 通过工厂对象调用 openSession 方法创建SqlSession 对 象 ;在 这 个 过 程 中 , 需 要 通 过TransactionFactory生成 Transaction 对象, 并且, 还需要创建核心执行器 Executor 对象, 之后, 通过这些对象来创建DefaultSqlSession对象, 至此, SqlSession对象创建成功。
之后, 通过 SqlSession 对象执行相应的操作, 如果执行成功, 调用 commit 方法提交事务; 如果失败, 调用rollback 方法事务回滚。最后, 调用 close 方法关闭session 资源。以上, 就是 MyBatis 的运行原理。
网友评论