使用MyBatis 实现Dao层,并使用Mapper动态代理

一个小案例

如果我不用id作为主键,而是用UUID作为主键,怎么操作?

第一种方法

    <insert id="insertUser" parameterType="com.bamzhy.bean.User">
        INSERT INTO tt_user VALUES (#{id},#{username},#{password},#{email},#{age});
    </insert>
    @Test
    public void test3() throws IOException {
        //使用Mybatis的api去实现
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //操作数据库的一个载体
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //返回一个对象
        User user = new User();
        //Universally Unique Identifier(UUID 通用唯一识别码)
        user.setId(UUID.randomUUID().toString());
        user.setUsername("haha4");
        user.setPassword("12345");
        user.setEmail("[email protected]");
        user.setAge(199191);
        int insert = sqlSession.insert("test.insertUser", user);
        sqlSession.commit();

        System.out.println("insert "+insert);
    }

第二种方法

  • 使用selectKey

    <insert id="insertUser" parameterType="com.bamzhy.bean.User">
        <!--keyProperty对应的是下边{}中的名称,resultType是其格式,order是执行时间在此条sql语句前还是语句后-->
        <selectKey keyProperty="id" resultType="string" order="BEFORE">
            SELECT UUID()
        </selectKey>
        INSERT INTO tt_user VALUES (#{id},#{username},#{password},#{email},#{age});
    </insert>

使用MyBatis ORM实现DAO层

案例2实现之前代码的重构

src下边的mybatis.xml和user.xml跟之前的没有区别(那些不用动)

  • 新增UserDaoImpl.java
    @Override
    public User findUserById(int id) throws IOException {
        //使用Mybatis的api去实现
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //操作数据库的一个载体
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //返回一个对象
        User user = sqlSession.selectOne("test.findUserById", id);
        System.out.println("user"+user);
        return null;
    }
  • 新增一个测试用例
    @Test
    public void findUserById() throws IOException {
        UserDao user=new UserDaoImpl();
        user.findUserById(2);
    }
  • 考虑到没必要每一次操作都new一个sqlSessionFactory,所以我们把new这个操作的过程放进DAO中
    这里写图片描述

对之前案例的反思

  • 有大量代码是重复的
  • SqlSessionFactory,应该是全局范围的,整个应用只有一个工厂。使用单例模式来实现。与spring集成了之后,由spring对其来进行单例管理。
  • SqlSession。它内部含有一块数据区域,操作数据库的时候是需要通过它去设置隔离级别等事务特性。如果放在成员变量中使用spring对其来进行单例管理,则在多线程的情况下会存在线程安全问题。所以应该将sqlSession声明在方法内部。 这样每个线程用自己的sqlSession,不共享数据,则不存在线程安全问题。

从全新角度出发解决问题(Mapper动态代理实现)

开发规范

  • Mapper接口的全限定名要和Mapper映射文件的namespace一致
    这里写图片描述
    这里写图片描述

  • Mapper接口的方法名称要和Mapper映射文件的statement id一致
    这里写图片描述 这里写图片描述

  • Mapper接口的方法参数类型要和Mapper映射文件的statement parameter Type类型一致,而且它的参数是一个(多个参数也没关系,可以使用map装进去)

  • Mapper接口的方法返回值类型要和Mapper映射文件的statement的Result Type一致
    这里写图片描述
    这里写图片描述

如果是List<>的话,需要保证其泛型类型与resultType保持一致(每一行的类型)

  • bean里边的xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bamzhy.dao.UserDao">

    <!--parameterType是参数的类型,以前的问号?用#{}代替-->
    <!--这一行SQL语句要映射到哪个类上要使用resultType指明-->
    <select id="findUserById" parameterType="int" resultType="com.bamzhy.bean.User">
        SELECT * FROM tt_user WHERE id=#{id};
    </select>

    <select id="findUserByName" parameterType="string" resultType="com.bamzhy.bean.User">
        SELECT * FROM tt_user WHERE username Like #{id};
    </select>

    <insert id="insertUser" parameterType="com.bamzhy.bean.User">
        <!--keyProperty对应的是下边{}中的名称,resultType是其格式,order是执行时间在此条sql语句前还是语句后-->
        <!--<selectKey keyProperty="id" resultType="string" order="BEFORE">-->
            <!--SELECT UUID()-->
        <!--</selectKey>-->
        <selectKey keyProperty="id" resultType="string" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO tt_user VALUES (#{id},#{username},#{password},#{email},#{age});
    </insert>

    <delete id="deleteUserById" parameterType="int">
        DELETE FROM tt_user WHERE id=#{id};
    </delete >

    <update id="updateUserById" parameterType="com.bamzhy.bean.User">
        UPDATE tt_user SET username=#{username},password=#{password} WHERE  id=#{id};
    </update>

</mapper>
  • Dao接口
package com.bamzhy.dao;

import com.bamzhy.bean.User;

import java.io.IOException;
import java.util.List;

public interface UserDao {
    User findUserById(int id) throws IOException;

    User finduUserByName(String username) throws IOException;

    int AddUser(User user) throws IOException;

    List<User> queryAllUser( ) throws IOException;
}
  • test
package com.bamzhy.test;

import com.bamzhy.bean.User;
import com.bamzhy.dao.UserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class test {

    SqlSessionFactory sqlSessionFactory ;
    UserDao dao;
    SqlSession sqlSession;

    //在任何一个测试方法之前执行
    @Before
    public void before() throws Exception {
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        sqlSession = sqlSessionFactory.openSession();

        dao = sqlSession.getMapper(UserDao.class);

    }
    //在任何一个测试方法之后执行
    @After
    public void After(){
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void test6() throws IOException {
        User userById = dao.findUserById(1);
        System.out.println("user=" + userById);
    }
}

使用Mapper动态代理的好处

  • 使用之前的session,selectOne(“test.findUserById”,1),通过字符串调用标签定义的SQL,一是容易出错,而是XML中的id修改以后那么用了这个id的程序就都得改,这样比较麻烦
  • 为了防止这些现象的出现,采用了Mapper方法

使用Mapper动态代理的流程

  • 我们定义一个接口类,里边函数名和需要与Bean中的XML文件定义的id保持一致。
  • 把Bean中的namespace替换成接口类的全类名
  • 获取session,并获取Mapper接口的代理对象(这个可用使用AOP放在方法执行前执行)
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession = sqlSessionFactory.openSession();
        //获取代理对象
        dao = sqlSession.getMapper(UserDao.class);
  • 调用代理对象方法,关闭session(也用AOP实现)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章