美文网首页
Java学习day-61:MyBatis框架(3)

Java学习day-61:MyBatis框架(3)

作者: 开源oo柒 | 来源:发表于2019-10-16 21:37 被阅读0次

一、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 的运行原理。

3.

4.

相关文章

网友评论

      本文标题:Java学习day-61:MyBatis框架(3)

      本文链接:https://www.haomeiwen.com/subject/yoxpmctx.html