Spring08之myBatis和Spring的整合史上最最完整版

一、maven中导入整合需要的jar包依赖

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.5</version>
    </dependency>
</dependencies>

注意:整合时对版本的要求
在这里插入图片描述

三、准备myBatis的项目(在未整合之前的)。

1.pojo类–Student

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Integer score;
    private Integer age;
    private Integer gender;
}

2.在repository包下新建Student类持久化的接口StudentRepository

public interface StudentRepository {
    int save(Student student);
    int update(Student student);
    int deleteById(long id);
    List<Student> findAll();
    Student findById(long id);
}

3.mapper.xml文件

定义了与接口中方法对应的具体的sql语句

<?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.xinbao.repository.StudentRepository">
    <insert id="save" parameterType="com.xinbao.pojo.Student">
                INSERT into student(id,name,score,age,gender) values(#{id},#{name},#{score},#{age},#{gender})
    </insert>
    <update id="update" parameterType="com.xinbao.pojo.Student">
        UPDATE student set score=#{score} WHERE id = #{id}
    </update>
    <delete id="delete" parameterType="long">
        DELETE from student WHERE id = #{id}
    </delete>
    <select id="findAll" resultType="com.xinbao.pojo.Student">
        SELECT * from student
    </select>
    <select id="findById" resultType="com.xinbao.pojo.Student">
        SELECT * from student WHERE id = #{id}
    </select>
</mapper>

说明:

1.标签对mapper内部,专门用于编写具体的sql语句,它提供了增删改查的标签对。
insert增
delete删
update改
select

2.对于增删改查的标签对,我们应该将它们看做一个个的方法。id 就是接口中的方法名,并且名称必须相同吻合。之后调用方法时,也会用到这个id值。

3.parameterType值是方法调用时传入的参数,这些方法操作的都都是一条一条的记录,因此参数要么是类的对象,要么是数值。如果是类的对象,一定要写全类名。

4.INSERT into student(id,name,score,age,gender) values(#{id},#{name},#{score},#{age},#{gender})
需要注意的是:values进行传值的时候,不要把真正的值写进来。我们应该用参数传值,并且用==#{参数名}==取值,防止sql注入问题。

5.namespace 中需要填写mapper接口的全限定名称

6.resultType 方法的返回值类型。一定要和接口中的返回值类型一致。对于增删改操作,返回值一定是int型的数据,表示操作的记录的条数,因此此时的resultType可以省略不写。对于查询操作,一定要写全类名。

4.myBatisConfig.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里可以有多个environment。
    每个environment都是一个可用的数据源。
    environments的default则是选择使用哪个environment的id。-->
    <environments default="a">
        <environment id="a">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://localhost:3306/yogurt?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"></property>
                <property name="username" value="root"></property>
                <property name="password" value="xin"></property>
            </dataSource>
        </environment>
    </environments>
<mappers>
    <mapper resource="com/xinbao/repository/StudentRepositoryMapper.xml"></mapper>
</mappers>

注意:在绑定mapper.xml文件时,resource中的路径不能再用点分隔,应该用斜杠。原因是:mapper文件的后缀需要用点分隔(.xml),如果前面的目录也用点分隔,编译器就不知道到底代表目录划分,还是后缀。

5.测试

@Test
    public void test2(){
    	//以类加载器的方式获取流来读取配置文件,也就是修建工厂的图纸
        InputStream stream =
                getClass().getClassLoader().getResourceAsStream("myBatisConfig.xml");
        //获取工人
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        
        //工人修建工厂,需要图纸stream
        SqlSessionFactory factory = builder.build(stream);
        SqlSession sqlSession = factory.openSession();


        //获取实现接口的代理类对象,该对象我们只用获取即可,是myBatis框架写好的。
        StudentRepository mapper = sqlSession.getMapper(StudentRepository.class);
        
        //查询操作
        List<Student> all = mapper.findAll();
        for(Student s:all){
            System.out.println(s);
        }
        Student number1 = mapper.findById(1);
        System.out.println(number1);

        //添加记录操作
        Student student1 = new Student(null, "辰辰", 15, 4, 1);
        Student student2 = new Student(null, "欣欣", 0, 25, 0);
        int i1 = mapper.save(student1);
        int i2 = mapper.save(student2);

        //删除记录操作
        int i = mapper.deleteById(5);
		
		//提交事务,所有增删改的事务,都必须要提交后才会执行。
        sqlSession.commit();
        sqlSession.close();
    }

说明:
1.读取配置文件得到stream的根本原因:builder造factory时需要myBatis配置文件中的数据源信息

2.StudentRepository mapper = sqlSession.getMapper(StudentRepository.class);参数是接口的运行时类。
整理一下思路
stream(图纸)–>builder(工人)–>factory(工厂)–>sqlsession(生成出的工具)–>mapper(实现接口的代理类对象)
然后所有的持久化操作都由mapper来调用方法。

四、开始整合myBatis和Spring

0.为什么myBatis要和Spring整合?(整合的目的)

其实很多时候我们学了,但是不懂为什么要这样做,不过原因其实也很简单。
在上面myBatis未整合的项目中,可以看到有个问题:
测试时内容冗余,需要造很多对象

Spring的优势是什么?
就是利用IoC管理bean,避免不停的造对象。这也是我们实现整合的目的和初衷!

1.在Spring的xml文件中配置数据源

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置数据源-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/yogurt?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"></property>
        <property name="username" value="root"></property>
        <property name="password" value="xin"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
</beans>

之前数据源的配置是在myBatis的配置文件中完成的,现在交由Spring来做。因此myBatis中该部分配置可以删除。

2.在Spring中造sqlSessionFactory。

有了数据源,就可以造工厂。(上面提到过)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置数据源-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/yogurt?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"></property>
        <property name="username" value="root"></property>
        <property name="password" value="xin2117372823"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>


    <!--配置SqlSessionFactory:sqlSessionFactory的创建需要数据源。-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"></property>
    </bean>

</beans>

3.SqlSessionFactory的配置中,还可以绑定myBatis.xml和mapper.xml。

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"></property>


    <!--还可以绑定myBatis.xml文件。这样myBatis.xml和Spring就连起来了。-->
    <property name="configLocation" value="myBatisConfig.xml"></property>
    <property name="mapperLocations" value="classpath:com/xinbao/mapper/StudentMapper.xml"></property>
</bean>

4.sqlSessionTemplate

工厂直接被spring容器管理了,但是还没有sqlSession。
在Spring中,我们使用sqlSessionTemplate替代sqlSession。
在创建sqlSessionTemplate时,需要factory作为构造器参数。一环扣一环。
原因:sqlSessionTemplate类中没有提供set方法,只能构造器注入。

<!--由sqlSessionTemplate创建sqlSessionTemplate,由于SqlSessionTemplate没有set方法,-->
<!--只能通过构造器传入factory参数。-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>

5.编写StudentMapper接口的实现类(为什么需要写实现类)

我重写的方法比之前接口中定义的少了几个(偷懒),需要自行根据自己定义的接口来重写方法哈。

public class StudentMapperImpl implements StudentMapper {

    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public int save(Student student) {
        StudentMapper mapper = sqlSessionTemplate.getMapper(StudentMapper.class);
        return mapper.save(student);
    }

    @Override
    public List<Student> selectById(long id) {
        StudentMapper mapper = sqlSessionTemplate.getMapper(StudentMapper.class);
        return mapper.selectById(id);
    }
}

可以看到,在实现类的内部,仍然是sqlSessionTemplate获取mapper对象,然后mapper对象调用mapper.xml中配置好的方法。
这里为什么要提供接口的实现类呢?不提供可以吗?当然可以!
按照原来的方式来:仍然运行成功。

@Test
public void test4(){
    ApplicationContext context = new
            ClassPathXmlApplicationContext("applicationContext.xml");
    SqlSessionTemplate sqlSession = (SqlSessionTemplate) context.getBean("sqlSession");
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    System.out.println(mapper.selectById(1));
}

但是这不符合Spring的习惯。
在Spring中,我们更喜欢通过获取bean的方式来获取对象,然后对象直接调用方法。
所以编写接口实现类的目的,其实是为了符合Spring的IoC约定。
将实现类交由spring的ioc容器管理,再通过getBean的方式获取实现类对象,也就是如下的方式。

@Test
public void test3(){
    ApplicationContext context = new
            ClassPathXmlApplicationContext("applicationContext.xml");
    StudentMapperImpl studentMapperImp = context.getBean("studentMapperImp", StudentMapperImpl.class);
    System.out.println(studentMapperImp.selectById(1));
}

所以我们再封装一个实现了接口的实体类,然后在spring中管理这个实体类的bean。

6.Spring的xml文件中注册管理实现类的bean,并注入属性值。

注意:该类中有sqlSessionTemplate的属性未赋值,需要在注册时注入值。
我们在实现类中提供了sqlSessionTemplate的set方法,所以property方式即可。

<bean id="studentMapperImp" class="com.xinbao.mapper.StudentMapperImpl">
    <property name="sqlSessionTemplate" ref="sqlSession"></property>
</bean>

7.测试

@Test
public void test2(){
    ApplicationContext context = new
            ClassPathXmlApplicationContext("spring-dao.xml");
    StudentMapperImpl studentMapperImp = context.getBean("studentMapperImp", StudentMapperImpl.class);
    System.out.println(studentMapperImp.selectById(1));
}

整理思路
1.读取配置文件。
2.获取接口实现类的对象。
3.对象调用接口中定义的方法。

五、再精简

1.在resources里new一个applicationContext.xml文件。

将spring-dao中的bean管理内容复制到applicationContext.xml中。
通过import将spring-dao文件引入进来。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">


    <import resource="spring-dao.xml"></import>


    <bean id="studentMapperImp" class="com.xinbao.mapper.StudentMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSession"></property>
    </bean>


</beans>

2.spring-dao.xml专注于数据库连接(数据源配置)和sqlSession对象的创建

这个文件几乎全是死东西了,除了路径需要根据情况改变外,其余都可以直接搬用。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置数据源-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/yogurt?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"></property>
        <property name="username" value="root"></property>
        <property name="password" value="xin"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <!--配置SqlSessionFactory:sqlSessionFactory的创建需要数据源。-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"></property>

        <!--还可以绑定myBatis.xml文件和mapper.xml文件。这样myBatis.xml和Spring就连起来了。-->
        <property name="configLocation" value="myBatisConfig.xml"></property>
        <property name="mapperLocations" value="classpath:com/xinbao/mapper/StudentMapper.xml"></property>
    </bean>

    <!--由sqlSessionFactory创建sqlSession,由于SqlSessionTemplate没有set方法,-->
    <!--只能通过构造器传入factory参数。-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
    </bean>

</beans>

六、总结

spring和myBatis整合后,可以发现Spring太霸道强大,myBatis的做的很多事情都被spring来做了。
比如myBatis的数据源配置、mapper文件注册等。
myBatis剩下的唯一有价值的东西就是那个mapper.xml文件。
在mapper.xml文件里定义的方法标签对、sql语句都仍然是数据持久化的核心部分。

所有与核心代码无关的部分,比如数据源配置、bean对象的管理、mapper.xml文件的绑定、myBatisConfig.xml文件的绑定、sqlSession对象的创建都是spring来做。

在spring管理又分出两个文件。
spring-dao.xml专门用于做数据源配置、mapper.xml文件的绑定、myBatisConfig.xml文件的绑定、sqlSession对象的创建
applicationContext.xml专门用于管理bean,并且import spring-dao.xml 的资源。
所以最后applicationContext.xml才是包含最多的文件,测试时也只用读取这个文件。

注意:整合以后,多出来一个实现接口的实体类。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值