美文网首页
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