spring框架-与mybatis的整合(二)--SM编程DAO层开发

1.到目前为止引入的依赖

spring  mybatis mysql   mybatis-spring  druid

2.编写spring.xml

整合:spring接管mybatis中SqlSessionFactory对象的创建
<!--创建数据源-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/sm_learn?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull"></property>
    <property name="username" value="root"></property>
    <property name="password" value="123456"></property>
</bean>
<!--创建sqlSessionFactory-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
    <!--依赖的数据源-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

3.建表

CREATE TABLE IF NOT EXISTS CF_USER_T(
    USER_ID INT PRIMARY KEY COMMENT'用户登录ID',
    USER_NAME VARCHAR(200) COMMENT'用户名',
    USER_AGE INT COMMENT'年龄',
    USER_SEX INT COMMENT'用户性别',
    USER_TEL VARCHAR(20) COMMENT'用户电话号码',
    USER_PASSWORD VARCHAR(20) COMMENT'用户登录密码'
) COMMENT'用户信息表'

4.实体类

package com.cf.testsmdao.entity;

import lombok.Data;

/**
 * User: 晨风
 * <p>
 * Author:
 * Date: 22:56
 */
@Data
public class User {
    private Long userId;
    private int userAge;
    private int userSex;
    private String userName;
    private String password;
    private String userTel;

    public User() {
    }

    public User(Long userId, int userAge, int userSex, String userName, String password, String userTel) {
        this.userId = userId;
        this.userAge = userAge;
        this.userSex = userSex;
        this.userName = userName;
        this.password = password;
        this.userTel = userTel;
    }
}

5.开发dao层接口

package com.cf.testsmdao.dao;

import com.cf.testsmdao.entity.User;

import java.util.List;

/**
 * @author yourname
 * @date 2021/4/16 23:04
 */
public interface UserDAO {
    void save();
    List<User> find();
}

6.开发mapper

<?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="com.cf.testsmdao.dao.UserDAO">


    <select id="find" resultType="com.cf.testsmdao.entity.User">
      select
      USER_ID userId,
      USER_NAME userName,
      USER_AGE userAge,
      USER_SEX userSex,
      USER_TEL userTel,
      USER_PASSWORD password from CF_USER_T


    </select>

</mapper>

7.启动工厂获取SqlSessionFactory

package com.cf.testsmdao.test;

import com.cf.testsmdao.dao.UserDAO;
import com.cf.testsmdao.entity.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * User: 裴晨风
 * <p>
 * Author:
 * Date: 23:34
 */
public class TestMapper {
    @Test
    public void test() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/cf/sm2/spring.xml");
        SqlSessionFactory sessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactoryBean");
        SqlSession sqlSession = sessionFactory.openSession();
        UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
        userDAO.find().forEach(System.out::println);
        //User(userId=1, userAge=18, userSex=1, userName=小一, password=a11111, userTel=11111)
        //User(userId=2, userAge=19, userSex=2, userName=小二, password=a22222, userTel=22222)
    }
}

8.改进

虽然学到这里,感觉框架的封装已经很妙了,但是我们可以从test中发现,每次要获取DAO,我们都需要走三个步骤。

1).获取SqlSessionFactory ->{SqlSessionFactory sessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactoryBean");}

2).通过SqlSessionFactory 创建SqlSession -> {SqlSession sqlSession = sessionFactory.openSession();}

3).通过SqlSession 获取到dao的mapper文件-> {UserDAO userDAO = sqlSession.getMapper(UserDAO.class);}

然后,我们通过调用dao层的方法后,会执行mapper中的对应方法的sql语句,对数据库进行crud。

但是如果每次调用dao层时,都要经过这三个步骤的话,未免太过繁琐。因为我们不关心取mapper的过程(创建mybatis的核心对象SqlSessionFactory->创建SqlSession ->sqlSession.getMapper(UserDAO.class)),我们只要最后获取到mapper就可以了,当然是一步到位最好。

如何一步到位呢?

首先,我们可以回想下spring的AOP思想,将这三步封装成一个前置通知是否可以呢?将切面设定为所有dao层内的方法,然后每次调用dao方法的时候,执行前置通知获取mapper。

思考了下,应该是不可以。对比下之前未整合mybatis时的AOP编程代码,可以看到,当时的dao层方法可以执行,是基于有其对应的实现类。而整合mybatis后,我的理解是此时的dao层的实现其实就是对应的mapper文件中的sql语句。而获取mapper正是dao层得以实现的必要条件。如果封装成前置通知,那大概意思就是这样了:执行dao的方法前,在前置通知中获取对应的mapper文件。其中有两点有待商榷:1.dao的方法能够执行么?2.通知的定义是对业务功能之外的附加功能的实现。即:前置通知可以是业务功能实现的必要条件吗?以我现在的只是储备量来思考的话,是不能够的。

mybatis想的很周到:

mybatis-spring jar包中的org.mybatis.spring.mapper.MapperFactoryBean已经封装了getMapper的过程

 <!-- 创建DAO组件类-->
    <!-- 创建userDAO-->
    <bean id="userDAO" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!-- 注入SqlSessionFactory-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
        <!-- 注入创建DAO接口类型  注入接口的全限定名 包.接口名-->
        <property name="mapperInterface" value="com.cf.testsmdao.dao.UserDAO"></property>
    </bean>

    <!-- 创建studentDAO-->
    <bean id="studentDAO" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!-- 注入SqlSessionFactory-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
        <!-- 注入创建DAO接口类型  注入接口的全限定名 包.接口名-->
        <property name="mapperInterface" value="com.cf.testsmdao.dao.studentDAO"></property>
    </bean>

于是一步到位,我们想要获取哪个mapper,只需要在配置文件中注入即可value="com.cf.testsmdao.dao.studentDAO"。

此时,再回顾一下整个整合的思路:

1.什么是复杂对象?复杂对象怎么创建?

a.复杂对象:不可通过new创建实例的对象

b.复杂对象怎么创建:创建对应bean类,在类中通过重写getObject自定义创建复杂对象

2.spring整合mybatis的切入点是什么?

掌握mybatis的核心对象的创建

3.SqlSessionFactory核心对象如何通过spring工厂创建?

a.引入mybatis-spring jar包

b.注入依赖-数据源dataSource

4.spring工厂创建SqlSessionFactory后,怎么通过SqlSessionFactory获取到dao的mapper文件?

a.SqlSessionFactory bean中  注入依赖--要获取的mapper文件

b.获取SqlSessionFactory 

c.通过SqlSessionFactory 创建SqlSession 

d.通过SqlSession 获取到dao的mapper文件

5.如何封装获取mapper的过程?或者说直接获取dao层?

a.引入org.mybatis.spring.mapper.MapperFactoryBean

b.注入依赖--含有mapper文件依赖的SqlSessionFactory bean

c.注入依赖--获取哪个dao的mapper文件

感想:

整合mybatis之前,通过spring生成一个对象是那么的简单,工厂中对象的路径一写,id一确定,要啥属性就注入啥,工厂启动后拿来对象就能用。

整合mybatis后,先是复杂对象的创建,然后再是复杂对象创建的封装,封装的过程中又伴随着许多复杂的依赖注入。所幸,结果是一样的,还是工厂启动后拿来就能用。

另:在工作中springboot用起来是真的方便,没有这么多依赖、配置。实现持久化也不需要先得到SqlSessionFactory 再得到xxx最后得到mapper。只要mapper中namespace关联上dao层路径,方法id一致,直接new出来就能实现。

会不会是,越高端的框架使用起来就越简单呢?然而当你用起来很简单的时候,你就忽略了他的底层实现,想都不会想一下。

希望我一直努力学下去,对框架封装的那些思想原理不再是一头雾水。

最好的软件是傻子都会用的。

但是身为一个开发者,不能真的像个傻子一样对自己使用的技术一无所知!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 夜莺2517阅读 127,806评论 1 9
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 12,728评论 28 53
  • 兔子虽然是枚小硕 但学校的硕士四人寝不够 就被分到了博士楼里 两人一间 在学校的最西边 靠山 兔子的室友身体不好 ...
    待业的兔子阅读 7,512评论 2 9
  • 信任包括信任自己和信任他人 很多时候,很多事情,失败、遗憾、错过,源于不自信,不信任他人 觉得自己做不成,别人做不...
    吴氵晃阅读 11,351评论 4 8