Spring+Mybatis实战

Spring+Mybatis实战

官方中文文档:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference

01 简介

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)

理念:简化开发,就是一个整合了现有技术框架的大杂烩

官网 : http://spring.io/

官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/

GitHub : https://github.com/spring-projects

Spring的优点

  • 方便解耦,简化开发 (高内聚低耦合) Spring就是一个大工厂(容器), Spring工厂是用于生成bean,可以将所有对象创建和依赖关系维护,交给Spring管理
  • AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持 只需要通过配置就可以完成对事务的管理,而无需手动编程
  • 方便程序的测试
    Spring对Junit4支持,可以通过注解方便的测试Spring程序
  • 方便集成各种优秀框架
    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis等)的直接支持,方便整合其他框架
  • 降低JavaEE API的使用难度
    Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

控制反转IOC和依赖注入

IOC和DI的区别:

  1. IOC:控制反转,把创建对象交给Spring进行配置
  2. DI: 依赖注入,向类里面的属性中赋值

Spring的面向切面编程(AOP)

将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面然后注入到目标对象(具体业务逻辑)中去。

02 Spring的基本使用

步骤

1)用maven创建一个项目,在 pom.xml 文件中加入 spring的依赖(jar包)

2)在 resource 目录下,编写 spring上下文配置文件,并定义要控制反转的类

<!-- 1) pom.xml文件添加-->
<dependencies>
      <!--测试相关-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
      <!--Spring核心基础依赖-->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>5.0.2.RELEASE</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.0.2.RELEASE</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>5.0.2.RELEASE</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-expression</artifactId>
          <version>5.0.2.RELEASE</version>
      </dependency>
      <!--日志相关-->
      <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
      </dependency>
      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
      </dependency>
      <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>RELEASE</version>
          <scope>compile</scope>
      </dependency>
  </dependencies>
<!-- 2) applicationContext.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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--把testDao对象的创建权交给Spring-->
    <bean id="testDao" class="dao.TestDaoImpl"></bean>

</beans>

注意:

  • bean 的 id是严格区分大小写的 如果id不存在会报错: NoSuchBeanDefinitionException

  • 如果容器中同一个类型的bean有多个,再根据类型获取的话就会报错: NoUniqueBeanDefinitionException

  • bean一般需要无参构造,spring会调用它来创建对象

  • 如果没有无参构造,需要给构造方法的参数赋值:

  • 默认情况下,每个类型的bean在容器中只有一个对象(单例) 多例,每用一次,创建一个新的对象, 如果配置多例

  • 初始化方法 和 销毁方法:

  • 单例:单例对象既会调用初始化方法,也会调用销毁方法

    ​ 多例:每使用一个多例对象都会调用初始化方法,但所有的多例对象都不会调用销毁方法

测试

创建dao包,在dao包下创建TestDao接口和TestDao接口的实现类,结构如下图:

image

//TestDao接口代码示例:
package dao;

public interface TestDao {
    public void sayHello();
}

//TestDaoImpl实现类代码示例:
package dao;

public class TestDaoImpl implements TestDao {
    @Override
    public void sayHello() {
        System.out.println("Hello,Spring!");
    }
}

//创建test包,在test包下创建测试类SpringTest
import dao.TestDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;

public class SpringTest {

    @Test
    public void demo(){
        //初始化Spring容器ApplicationContext,加载配置文件
        ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过容器获取testDao实例
        TestDao testDao = (TestDao) application.getBean("testDao");
        testDao.sayHello();
    }
}

03 Spring依赖注入方法

依赖注入的三种方式:

    ### 1) set注入:   

property 配合 setXXX() 方法

public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
  }         
//spring.xml 配置:
<bean id="userService" class="com.chen.service.UserService">
        <!-- 1) set注入-->
        <property name="userDao" ref="userDao"/>
</bean>
  ###  2) 构造注入: 

constructor-arg 配合构造函数

public UserService(UserDao userDao) {
    this.userDao = userDao;
}
<!--spring.xml 配置:-->

<bean id="userService" class="com.chen.service.UserService"> 
   <!-- 2) 构造注入 -->
  <constructor-arg index="0" ref="userDao"/>
</bean>

3) 注解注入:

@AutoWired | @Resource 配合 context:annotation-config/(启动注解,否则spring无法解析注解) 利用这个注解完成属性的赋值,把它加在需要注入的属性上, 或set方法上,或构造方法上

// 3) 注解注入 : 利用反射,找到该变量的类型,自动赋值

 @Autowired | @Resource
 private UserDao userDao;
<!--spring.xml 配置:,-->     
<!-- 3) 启动注解 -->
<context:annotation-config/>

04 properties注入方法

将 *.properties 注入到spring.xml中:
方便以后修改,只修改 *.properties 中的内容,不改动 spring.xml 中的配置

<!--
   读取properties 文件 
        location="文件位置" 
        placeholder 占位符
-->
<context:property-placeholder location="classpath:jdbc.properties"/>
 
 
<!-- 
     可以利用 ${key} 获取 *.properties 文件中的值
-->
<bean id="productDao" class="com.westos.dao.ProductDao">
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>
 
注解方式 @Value 也可以完成这种 值注入
@Value("${properties中的key}")

Spring和Mybatis整合

方法一: 通过 XXXMapper.xml 映射文件整合
1)配置 pom.xml 文件,加入所需要的依赖

<dependencies>
    <!-- spring jar 包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
 
    <!-- junit jar 包-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
 
    <!-- mysql 的驱动包-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.12</version>
    </dependency>
 
    <!--logback 日志包-->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
 
    <!-- mybatis jar 包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
 
    <!-- 数据库连接池 alibaba 的 druid  -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.7</version>
    </dependency>
 
    <!-- mybatis与spring整合的jar包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.1</version>
    </dependency>
 
    <!--spring管理的 jdbc ,以及事务相关的-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.17.RELEASE</version>
    </dependency>
</dependencies>

2)把关键对象的创建交给 spring 控制反转(IOC),生成:连接池对象,SqlSessionFactory工厂类,SqlSession对象>

<?xml version="1.0" encoding="UTF-8" ?>
<!-- xmlns 是xml的命名空间
    要引入新的 context命名空间
-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd">
 
    <!--
       读取 jdbc.properties 中的内容
            property-placeholder: 占位符
            location: 属性文件的位置
    -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
 
    <!-- 1) 获得数据库连接池对象,并交由 spring 同一管理 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
 
        <!-- 连接数据库的驱动,连接字符串,用户名和登录密码-->
        <property name="driverClassName" value="${drivername}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${password}"/>
 
        <!-- 数据池中最大连接数和最小连接数-->
        <property name="maxActive" value="${max}"/>
        <property name="minIdle" value="${min}"/>
    </bean>
 
    <!-- 2) 获取 SqlSessionFactory 对象,并交由 spring 管理-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入连接池
         给 sqlsessionFactory 的属性 dataSource 赋值
            ref="引用该 spring容器 中的另一个 bean的id"
        -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 注入 映射文件 mapper
         给 sqlsessionFactory 的属性 mapperLocation 赋值
           value="映射文件 XXXmapper.xml 的相对路径"
          -->
        <property name="mapperLocations" value="classpath:com/chen/mapper/*.xml"/>
    </bean>
 
    <!-- 3) 获取 SqlSession 对象,并交由 spring 管理  用SqlSessionTemplate得到的SqlSession可以不用我们自己操心事务的管理,以及关闭操作-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 给 SqlSessionTemplate 的构造函数赋值-->
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
</beans>

3)配置 XXXMapper.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="com.chen.mapper.ProductMapper">
    <select id="selectPage" parameterType="map" resultType="com.chen.entity.Product">
        select id,name from product limit #{start},#{size}
    </select>
</mapper>

​ 4) 使用 SqlSession 进行操作

public class SpringMybatisTest {
    /*
    * 1. 创建spring容器
           根据xml文件应用程序Context容器(上下文)
           classpath指配置文件的位置, 起点有java, resources. 写路径时相对这个起点去写
    * */
    static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
 
    @Test
    public void test1(){
 
        /* 得到 SqlSession 对象*/
        SqlSession sqlSession = (SqlSession) context.getBean("sqlSession");
 
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("start",0);
        map.put("size",5);
 
        // 调用 Mapper映射文件里的方法
        List<Product> list = sqlSession.selectList("com.chen.mapper.ProductMapper.selectPage", map);
 
        for (Product product : list) {
            System.out.println(product);
        }
    }
}

方法二:通过 Mapper接口的方式整合

1) 在配置文件 pom.xml 中加入依赖

 <dependencies>
        <!-- spring 容器相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.17.RELEASE</version>
        </dependency>
        <!-- spring jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.17.RELEASE</version>
        </dependency>
        <!-- mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!-- 与spring整合 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
        </dependency>
        <!-- 连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.7</version>
        </dependency>
        <!-- 日志
         slf4j 接口               logback 是实现
         commons-logging 接口     桥接 - slf4j
        -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- 日志桥接 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>
 
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2)在 spring.xml 配置文件中

    <!-- 1) 读取properties中的内容-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
 
    <!-- 2) 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${drivername}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${password}"/>
        <property name="maxActive" value="${max}"/>
        <property name="minIdle" value="${min}"/>
    </bean>
 
    <!-- 3) 获取 SqlSessionFactory 工厂类-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean>
 
    <!-- 4) 搜索有哪些 mapper 实现类,把mapper接口自动配置成 spring 中的 <bean>-->
    <bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 
        <!-- name="basePackage":(起始)包名, 从这个包开始扫描-->
        <property name="basePackage" value="com.chen.mapper"/>
 
    </bean>

3)编写 mapper接口

public interface ProductMapper {
 
    /**
     * 增
     */
    @Insert("insert into product(name,price) values(#{name},#{price})")
    void insert(Product product);
 
    /**
     * 删
     */
    @Delete("delete from product where id=#{id}")
    void delete(int id);
 
    /**
     * 改
     */
    @Update("update product set name=#{name},price=#{price} where id=#{id}")
    void update(Product product);
 
    /**
     * 查: 根据id查
     */
    @Select("select id,name,price from product where id=#{id}")
    Product findById(int id);
 
    /**
     * 分页查询(物理分页)
     */
    @Select("select id,name,price from product limit #{start},#{size}")
    List<Product> findByPage(Map map);
 
    /**
     * 分页查询(逻辑分页)
     */
    @Select("select id, name,price from product")
    List<Product> PageLogical(RowBounds rowBounds);
 
    /**
     *  当 *.java -> *.class时,方法的参数名信息会丢失,所以再按m名称去找,则无法找到该参数名
     *  mybatis的mapper映射中,默认方法最多只接收一个参数, 多个参数需要用map或list等集合包装
     *  要突破这个限制需要使用@Param注解,把它加在方法参数上,建立方法参数和sql中#{}之间的联系:
     * @param m
     * @param n
     * @return
     */
    @Select("select id, name,price from product limit #{start},#{size}")
    List<Product> Page(@Param("start")int m,@Param("size")int n);
 
    /**
     * 动态sql,配合 XXXMapper.xml 映射文件进行 动态sql拼接
     *  注意: 1) 目录结构要一致
     *         2) xml中 namespace的取值与接口的包名类名要一致
     *         3) 接口中的方法名与xml中标签id对应
     *         4) 接口中的方法名不能重复(不支持重载)
     */
    void deleteByIds(List<Integer> ids);
}

4)使用 XXXMapper.xml 配合 Mapper接口 进行 动态 SQL 的拼接

<mapper namespace="com.chen.mapper.ProductMapper">
 
    <!-- id名必须和ProductMapper接口中的方法名保持一致-->
    <delete id="deleteByIds" parameterType="list" >
        delete from product where id in
        <foreach collection="list" item="i" open="("  separator="," close=")">
            #{i}
        </foreach>
    </delete>
 
</mapper>
  1. 测试Mapper接口
public class MapperTest {
    //获得spring容器
    static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
 
    @Test
    public void test1(){
        // 利用反射,得到spring自动配置的 ProductMapper 的 <bean>
        ProductMapper mapper = context.getBean(ProductMapper.class);
        Product p = new Product();
        p.setName("kobe");
        p.setPrice(6666.66);
        mapper.insert(p);
    }
}

END 参考博客地址:

https://blog.csdn.net/qq_42371269/article/details/83505269

还没看完,有时间回来继续看

posted @ 2021-08-03 12:33  Lexie——01  阅读(101)  评论(0)    收藏  举报