【Mybatis04】传统Dao开发及其弊端

思路:原始Dao开发方式需要程序员编写Dao接口和Dao实现类

由第一篇博客的架构图可知:

    SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。 
    通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
    SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
    SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
    SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作方法。 
    每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的(因为SqlSession底层对应的是Connection连接)。因此最佳的范围是请求或方法范围。

**

UserDao接口

**

public interface UserDao {
    /**
     * 查全部
     * @return
     */
    public List<User> findAll();
    /**
     * 保存用户
     * @param user
     */
    public void save(User user);

    /**
     * 更新用户
     * @param user
     */
    public void update(User user);

    /**
     * 根据id删除用户
     * @param id
     */
    public void del(Integer id);
}


UserDaoImpl实现类

执行sql语句,从数据库中查询出来的数据封装到User对象中,返回结果集。
实现类中注入SqlSessionFactory,暂时通过构造方法注入。
在查询、更新等方法中创建SqlSession,因为SqlSession线程不安全。
执行增删改方法,SqlSession需要先commit再close。

public class UserDaoImpl implements UserDao {
    //所有的方法共用的factory对象,应该是属于应用级别
    private SqlSessionFactory sessionFactory;

    public UserDaoImpl(SqlSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public List<User> findAll() {
        //每一个方法应该获取一个SqlSession对象,用完应该立即关闭,因为线程不安全
        SqlSession sqlSession = sessionFactory.openSession();
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        sqlSession.close();
        return userList;
    }
//执行增删改,sqlSession需要comnit操作
    @Override
    public void save(User user) {
        SqlSession sqlSession = sessionFactory.openSession();
        sqlSession.insert("userMapper.save",user);
        sqlSession.commit();
        sqlSession.close();
    }

    @Override
    public void update(User user) {
        SqlSession sqlSession = sessionFactory.openSession();
        sqlSession.update("userMapper.update" , user);
        sqlSession.commit();
        sqlSession.close();
    }

    @Override
    public void del(Integer id) {
        SqlSession sqlSession = sessionFactory.openSession();
        sqlSession.delete("userMapper.del",id);
        sqlSession.commit();
        sqlSession.close();
    }
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
    <select id="findAll" resultType="com.itheima.domain.User">
        select * from user
    </select>

    <insert id="save" parameterType="com.itheima.domain.User">
        insert into user values(null ,"${username}",#{password},#{sex},#{address},#{birthday})
    </insert>

    <update id="update" parameterType="com.itheima.domain.User">
        update user set username=#{username},password=#{password},sex=#{sex},address=#{address}
        where id = #{id}
    </update>
    <delete id="del" parameterType="java.lang.Integer">
        delete from user where id = #{value}
    </delete>
</mapper>

由第一篇博客的架构图可知,总的配置文件SqlMapConfig.xml通过<mapper resource=…/>引入XXXMapper.xml映射文件,程序UserMapper.xml中的namespace+id作为底层Configuration类中Map<String,Mapper>的key来定位sql语句,用Mapper对象(其中包含sql,resultType,parameterType)作为value来存储sql。

SqlMapConfig.xml

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb_331"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/itheima/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

测试程序TestMybatisDao.java

public class TestMybatisDao {
    SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void init(){
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindAll(){

        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        List<User> userList = userDao.findAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testSave(){

        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        User user = new User();
        user.setUsername("小明");
        user.setPassword("xiaoming");
        user.setSex("男");
        user.setAddress("北京房山");
        user.setBirthday("2018-08-08");
        userDao.save(user);
    }
}

传统Dao开发存在的问题:

  • Dao实现类存在大量重复代码
  • 调用SqlSession方法时,将statement的id(也就是namespace.id,比如userMapper.findAll)硬编码了
  • SqlSession的方法中,要求传入的参数是Object类型的,也就是说,如果传错参数,运行时才会报错,不利于开发

猜你喜欢

转载自blog.csdn.net/weixin_44212815/article/details/93020847