Spring学习总结(五)——Spring整合MyBatis(Maven+MySQL)二
目录
接着上一篇博客《Spring 整合 MyBatis(Maven+MySQL)一》继续。
Spring 的开放性和扩张性在 J2EE 应用领域得到了充分的证明,与其他优秀框架无缝的集成是 Spring 最为强大的功能。Spring 类似电脑的主板,可以将许多部件集成在一起协调工作。
一、在 Web 项目中启动 Spring 容器
在 Web 项目中当 Web 容器启动时我们要同时启动 Spring 容器,有三种办法,第一种使用监听器启动,第二使用 Servlet 启动,第三使用 MVC 框架的扩展点启动,这里主要选择第一种,因为监听器的启动时机早于 Servlet。强烈建议使用办法一。
1.1、使用监听器启动 Spring 容器
我们需要使用到 Spring 定义好的一个监听器:org.springframework.web.context.ContextLoaderListener,该监听器在包 Spring-web.x.x.x.jar 下,修改 pom.xml 文件,添加依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency>
修改 web.xml 文件,新增监听器声明,代码如下:
<listener> <description>Spring 容器启动监听器</description> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
当监听器在启动 Spring 容器时会自动查找 Web-INF/lib 目录下名为 applicationContext.xml 配置文件,当然也可以设置参数指定配置文件的具体位置,特别是有多个配置文件的情况,指定办法如下:
<listener> <description>Spring 容器加载监听器</description> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param>
如果有多个配置文件则可以通过逗号分开。怎么判断是否启动成功,则可以参考本文第二点,获得 ApplicationContext 实例,也可以查看 tomcat 启动时的信息,如果没有出现错误且能找到如下说明基本成功。
启动失败也有几种可能,如 applicationContext.xml 文件的路径错误;找不到类 ContextLoaderListener;如果提示找不到类,很可能是因为没有将 Maven 依赖的包发布出去,可以在项目属性中设置,如下所示:
1.2、使用 Servlet 方式启动 Spring 容器
方法与 1.1 基本相同,只是配置有小的区别,修改 web.xml 的具体内容如下:
<servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </ servlet > <context-param> <param-name>contextConfigLocation</param-name> <!-- 多个配置文件之间以“,”隔开 --> <param-value> classpath:beans1.xml,classpath:beans2.xml... </param-value> </context-param>
需要注意的是两者都是继承类 ContextLoader,但从 Spring3.0 开始已经移除了 ContextLoaderServlet,用 ContextLoaderListener 的方式替代。第 3 种启动方式只有在特定的框架中才有效,所以不多用。
二、获取 ApplicationContext 实例
当 web 容器启动时 Spring 容器如果也成功启动了,则可以在整个 web 应用程序中获得 ApplicationContext 完成 IOC、AOP 及 Spring 的其它功能,获得 ApplicationContext 的常用方法有两种:
2.1、使用工具类 WebApplicationContextUtils 获得 Spring 容器
2.1.1、定义一个 Service 类,BookTypeService 代码如下:
package com.zhangguo.Spring61.service;import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.zhangguo.Spring61.entities.BookType;
import com.zhangguo.Spring61.mapping.BookTypeDAO;/*
图书类型服务
*/
@Service
public class BookTypeService {@Resource
BookTypeDAO bookTypeDAO;public List<BookType> getAllBookTypes() {
System.err.println("一些被省去的业务");
return bookTypeDAO.getAllBookTypes();
}
}
@Service 表示 Spring 容器将自动管理 BookTypeService 实例,@Resource 表示自动装配,会自动从 Spring 容器中找到类型为 BookTypeDAO 的 Bean 完成 bookTypeDAO 字段的初始化。
2.1.2、定义一个 Servlet,BookTypeList Servlet 代码如下:
package com.zhangguo.Spring61.action;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import com.zhangguo.Spring61.service.BookTypeService;
@WebServlet("/BookTypeList.do")
public class BookTypeList extends HttpServlet {
private static final long serialVersionUID = 1L;BookTypeService bookTypeService; @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在当前上下文中获得Spring容器</span> WebApplicationContext ctx=<span style="color: rgba(0, 0, 0, 1)">WebApplicationContextUtils.getWebApplicationContext(getServletContext()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从容器中获得bean</span> bookTypeService=ctx.getBean(BookTypeService.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doGet(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { PrintWriter writer</span>=<span style="color: rgba(0, 0, 0, 1)">response.getWriter(); writer.print(bookTypeService.getAllBookTypes().size()); } </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doPost(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { doGet(request, response); }
}
在 Servlet 中我们重写了父类的 init 方法,注意如果重写带参数的那个 init 方法 init(ServletConfig config),则一定要记得调用父类的 init 方法完成参数的初始化,即不要删除 super.init(config),如果不这样将获不到 servlet 下上文; 在 init 方法中我们通过 WebApplicationContextUtils 类获得得了 Spring 容器。
此时的 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" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">属性占位文件引入,可以通过${属性名}获得属性文件中的内容 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:property-placeholder </span><span style="color: rgba(255, 0, 0, 1)">location</span><span style="color: rgba(0, 0, 255, 1)">="classpath:db.properties"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">定义一个jdbc数据源,创建一个驱动管理数据源的bean </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="com.mchange.v2.c3p0.ComboPooledDataSource"</span><span style="color: rgba(255, 0, 0, 1)"> destroy-method</span><span style="color: rgba(0, 0, 255, 1)">="close"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClass"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.driver}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="jdbcUrl"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.url}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="user"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.uid}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.pwd}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="acquireIncrement"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="5"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="initialPoolSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="10"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="minPoolSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="5"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="maxPoolSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="20"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">定义一个jdbc数据源,创建一个驱动管理数据源的bean </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSourceBak"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.jdbc.datasource.DriverManagerDataSource"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClassName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.driver}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="url"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.url}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="username"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.uid}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.pwd}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">创建一个sql会话工厂bean,指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionFactoryBean"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">类型别名包,默认引入com.zhangguo.Spring61.entities下的所有类 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="typeAliasesPackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.entities"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">指定sql映射xml文件的路径 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="mapperLocations"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="classpath:com/zhangguo/Spring61/mapping/*Mapper.xml"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">自动扫描映射接口 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.mapper.MapperScannerConfigurer"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定sql会话工厂,在上面配置过的 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactoryBeanName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定基础包,即自动扫描com.zhangguo.Spring61.mapping这个包以及它的子包下的所有映射接口类 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="basePackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.mapping"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 创建一个sqlSession对象 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSession"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionTemplate"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">index</span><span style="color: rgba(0, 0, 255, 1)">="0"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">自动扫描组件 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:exclude-filter </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="aspectj"</span><span style="color: rgba(255, 0, 0, 1)"> expression</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.dao.*"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy </span><span style="color: rgba(255, 0, 0, 1)">proxy-target-class</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy</span><span style="color: rgba(0, 0, 255, 1)">></span>
</beans>
运行结果:
2.2、实现接口 ApplicationContextAware
当一个类实现了 org.springframework.context.ApplicationContextAware 接口时且实现该接口的类被 Spring 容器管理,则 Spring 容器会自动意识到需要调用接口中的方法 setApplicationContext 设置当前的 Spring 上下文。通俗说实现这个接口可以方便获得 Spring 上下文。该接口如下:
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;/**
-
Interface to be implemented by any object that wishes to be notified
-
of the {@link ApplicationContext} that it runs in.
-
<p>Implementing this interface makes sense for example when an object
-
requires access to a set of collaborating beans. Note that configuration
-
via bean references is preferable to implementing this interface just
-
for bean lookup purposes.
-
<p>This interface can also be implemented if an object needs access to file
-
resources, i.e. wants to call {@code getResource}, wants to publish
-
an application event, or requires access to the MessageSource. However,
-
it is preferable to implement the more specific {@link ResourceLoaderAware},
-
{@link ApplicationEventPublisherAware} or {@link MessageSourceAware} interface
-
in such a specific scenario.
-
<p>Note that file resource dependencies can also be exposed as bean properties
-
of type {@link org.springframework.core.io.Resource}, populated via Strings
-
with automatic type conversion by the bean factory. This removes the need
-
for implementing any callback interface just for the purpose of accessing
-
a specific file resource.
-
<p>{@link org.springframework.context.support.ApplicationObjectSupport} is a
-
convenience base class for application objects, implementing this interface.
-
<p>For a list of all bean lifecycle methods, see the
-
{@link org.springframework.beans.factory.BeanFactory BeanFactory javadocs}.
-
@author Rod Johnson
-
@author Juergen Hoeller
-
@author Chris Beams
-
@see ResourceLoaderAware
-
@see ApplicationEventPublisherAware
-
@see MessageSourceAware
-
@see org.springframework.context.support.ApplicationObjectSupport
-
@see org.springframework.beans.factory.BeanFactoryAware
*/
public interface ApplicationContextAware extends Aware {/**
- Set the ApplicationContext that this object runs in.
- Normally this call will be used to initialize the object.
- <p>Invoked after population of normal bean properties but before an init callback such
- as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
- or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
- {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
- {@link MessageSourceAware}, if applicable.
- @param applicationContext the ApplicationContext object to be used by this object
- @throws ApplicationContextException in case of context initialization errors
- @throws BeansException if thrown by application context methods
- @see org.springframework.beans.factory.BeanInitializationException
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
为了达到目的,我们现在创建一个名为 CtxUtil.java 的类,实现该接口,代如下:
package com.zhangguo.Spring61.action;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;@Component
public class CtxUtil implements ApplicationContextAware {</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> ApplicationContext springCtx; @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setApplicationContext(ApplicationContext applicationContext) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> BeansException { springCtx</span>=<span style="color: rgba(0, 0, 0, 1)">applicationContext; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根据名称获得容器中的bean</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> Object getBean(String name){ </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> springCtx.getBean(name); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根据类型获得容器中的bean</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <T> T getBean(Class<T><span style="color: rgba(0, 0, 0, 1)"> clazz){ </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> springCtx.getBean(clazz); }
}
为了让 Spring 容器在加载时能扫描到该类,我们在类上注解了 @Component;其实也可以直接在 ApplicationContext.xml 中新增一个 bean,如下所示:
<bean id="ctxUtil" class="com.zhangguo.Spring61.action.CtxUtil"></bean><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">自动扫描组件 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:exclude-filter </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="aspectj"</span><span style="color: rgba(255, 0, 0, 1)"> expression</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.dao.*"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
测试代码如下:
package com.zhangguo.Spring61.action;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import com.zhangguo.Spring61.service.BookTypeService;
@WebServlet("/BookTypeSize.do")
public class BookTypeSize extends HttpServlet {
private static final long serialVersionUID = 1L;BookTypeService bookTypeService; @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从容器中获得bean</span> bookTypeService=CtxUtil.getBean(BookTypeService.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doGet(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { PrintWriter writer</span>=<span style="color: rgba(0, 0, 0, 1)">response.getWriter(); writer.print(bookTypeService.getAllBookTypes().size()); } </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doPost(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { doGet(request, response); }
}
运行结果同 2.1。
三、基于注解的声明式事务管理配置
MyBatis-Spring 利用了存在于 Spring 中的 DataSourceTransactionManager 管理事务。
一旦 Spring 的 PlatformTransactionManager 配置好了, 你可以在 Spring 中以你通常的做法来配置事务。@Transactional 注解和 AOP 方式的配置都是支持的。在事务处理期间, 一个单独的 SqlSession 对象将会被创建和使用。当事务完成时, 这个 session 会以合适的方式提交或回滚。一旦事务创建之后,MyBatis-Spring 将会透明的管理事务。在你的 DAO 类中就不需要额外的代码了。
我们先使用一个简单的示例,证明没有事务时的状态:
PrintWriter writer=response.getWriter(); BookType entity1=new BookType(); entity1.setTypeName("中国文学");BookType entity2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BookType(); entity1.setTypeName(</span>"外国文学"); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">请注意这是是entity1</span> writer.print(bookTypeService.addDouble(entity1, entity2));</pre>
当运行时会发现有异常,因为 entity2 的 typeName 属性是 null,报异常了;按照事务的特性两条记录要么都添加成功要么都添加不成功。但查看数据库会发现,有一个对象的数据被添加成功了,另一个则失败了,这不符合原子特性。
为了解决上面的问题,我们引入 Spring 中的事务与 MyBatis-Spring 的事务管理。一定要记得添加 Spring-tx.jar 的依赖。修改 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" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">属性占位文件引入,可以通过${属性名}获得属性文件中的内容 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:property-placeholder </span><span style="color: rgba(255, 0, 0, 1)">location</span><span style="color: rgba(0, 0, 255, 1)">="classpath:db.properties"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">定义一个jdbc数据源,创建一个驱动管理数据源的bean </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="com.mchange.v2.c3p0.ComboPooledDataSource"</span><span style="color: rgba(255, 0, 0, 1)"> destroy-method</span><span style="color: rgba(0, 0, 255, 1)">="close"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClass"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.driver}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="jdbcUrl"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.url}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="user"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.uid}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.pwd}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="acquireIncrement"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="5"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="initialPoolSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="10"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="minPoolSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="5"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="maxPoolSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="20"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">定义一个jdbc数据源,创建一个驱动管理数据源的bean </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSourceBak"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.jdbc.datasource.DriverManagerDataSource"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClassName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.driver}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="url"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.url}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="username"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.uid}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.pwd}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">创建一个sql会话工厂bean,指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionFactoryBean"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">类型别名包,默认引入com.zhangguo.Spring61.entities下的所有类 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="typeAliasesPackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.entities"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">指定sql映射xml文件的路径 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="mapperLocations"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="classpath:com/zhangguo/Spring61/mapping/*Mapper.xml"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">自动扫描映射接口 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.mapper.MapperScannerConfigurer"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定sql会话工厂,在上面配置过的 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactoryBeanName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定基础包,即自动扫描com.zhangguo.Spring61.mapping这个包以及它的子包下的所有映射接口类 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="basePackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.mapping"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 创建一个sqlSession对象 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSession"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionTemplate"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">index</span><span style="color: rgba(0, 0, 255, 1)">="0"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="ctxUtil"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.action.CtxUtil"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span>
<!--声明式事务管理 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="jdbcDataSource"></property>
</bean>
<!--声明支持使用注解管理事务 -->
<tx:annotation-driven transaction-manager="txManager"/><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">自动扫描组件 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:exclude-filter </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="aspectj"</span><span style="color: rgba(255, 0, 0, 1)"> expression</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.dao.*"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy </span><span style="color: rgba(255, 0, 0, 1)">proxy-target-class</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy</span><span style="color: rgba(0, 0, 255, 1)">></span>
</beans>
请注意,加粗字体的部分是新增的。 修改后的 BookTypeDAO 接口如下:
package com.zhangguo.Spring61.mapping;import java.util.List;
import com.zhangguo.Spring61.entities.BookType;
/**
- 图书类型数据访问接口
/
public interface BookTypeDAO {
/
* 获得所有图书类型
*/
public List<BookType> getAllBookTypes();</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 添加新的图书类型 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> add(BookType entity);
}
修改后的 BookTypeMapper.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.zhangguo.Spring61.mapping.BookTypeDAO"> <!--id 应该是接口中的方法,结果类型如没有配置别名则应该使用全名称 --> <select id="getAllBookTypes" resultType="BookType"> select id,typeName from booktypes </select><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">insert </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="add"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="BookType"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> insert into booktypes(typeName) values(#{typeName}) </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(0, 0, 255, 1)">></span>
</mapper>
修改后的 BookTypeService 类如下:
package com.zhangguo.Spring61.service;import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.zhangguo.Spring61.entities.BookType;
import com.zhangguo.Spring61.mapping.BookTypeDAO;/*
图书类型服务
*/
@Service
public class BookTypeService {@Resource
BookTypeDAO bookTypeDAO;public List<BookType> getAllBookTypes() {
System.err.println("一些被省去的业务");
return bookTypeDAO.getAllBookTypes();
}@Transactional
public int addDouble(BookType entity1,BookType entity2){
int rows=0;
rows+=bookTypeDAO.add(entity1);
rows+=bookTypeDAO.add(entity2);
return rows;
}
}
在方法 addDouble 上增加了一个注解 @Transactional,用于显式声明该方法需要事务处理,如果把该注解移除则不会拥有事务特性。
测试的 Servlet 代码如下:
package com.zhangguo.Spring61.action;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import com.zhangguo.Spring61.entities.BookType;
import com.zhangguo.Spring61.service.BookTypeService;@WebServlet("/BookTypeAdd.do")
public class BookTypeAdd extends HttpServlet {
private static final long serialVersionUID = 1L;BookTypeService bookTypeService; @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从容器中获得bean</span> bookTypeService=CtxUtil.getBean(BookTypeService.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doGet(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { PrintWriter writer</span>=<span style="color: rgba(0, 0, 0, 1)">response.getWriter(); BookType entity1</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BookType(); entity1.setTypeName(</span>"量子力学"<span style="color: rgba(0, 0, 0, 1)">); BookType entity2</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BookType(); entity1.setTypeName(</span>"天体物理"); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">请注意这是是entity1,entity2的typeName属性为空</span>
writer.print(bookTypeService.addDouble(entity1, entity2));
}</span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doPost(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { doGet(request, response); }
}
entity2 因为没有 typeName 属性,添加时会异常,有事务存在,则数据库并没有变化,entity1 与 entity2 都未添加到数据库中。
除了使用声明式事务管理,也可以使用 AOP 进行事务拦截,参考代码如下:
<!-- 拦截器方式配置事物 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="append*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="repair" propagation="REQUIRED" /> <tx:method name="delAndRepair" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="transactionPointcut" expression="execution(* com.service..*Impl.*(..))" /> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /> </aop:config>
小结:声明式事务管理需要根据实际情况编码注解方法要不要事务处理,拦截方式配置事务则是根据方法名统一处理,一般查询是不需要事务参与的。在上面的配置中 REQUIRED 则表示需要事务支持,而 SUPPORTS 则不需要事务支持。