首页 > 代码库 > 由“单独搭建Mybatis”到“Mybatis与Spring的整合/集成”

由“单独搭建Mybatis”到“Mybatis与Spring的整合/集成”

在J2EE领域,Hibernate与Mybatis是大家常用的持久层框架,它们各有特点,在持久层框架中处于领导地位。

本文主要介绍Mybatis(对于较小型的系统,特别是报表较多的系统,个人偏向Mybatis),对于它,个人比较喜欢的是:

  • 使用简单、方便;
  • 支持的XML动态SQL的编写,方便浏览、修改,同时降低SQL与应用程序之间的耦合。

不喜欢的是:

  • 出现错误时,调试不太方便

本文主要介绍Mybatis的搭建,是学习Mybatis过程后整理的札记,其中包括“单独搭建Mybaits”和常用的“Mybatis与Spring的整合”。

 

一、数据库的准备

因为Mybatis是持久层框架,毫无疑问,是需要操作数据库的。所以,在搭建之前,我们需要先创建一个简单的表。

create table T_USER_TEST_1407(  USERNAME VARCHAR2(255),  PASSWORD VARCHAR2(255))
SQL - DDL - Create Table

 

插入一些数据,以作查询的测试。

insert into T_USER_TEST_1407 (USERNAME, PASSWORD)values (nick, Optimistic,Confident,Love - 1);
SQL - DML - Insert table

 

二、单独搭建Mybaits

1)环境准备、版本说明

此工程使用JDK1.6 + mybatis-3.2.4 + Oracle11g。

新建一个Web工程,由于只构建Mybatis,只引用Mybatis和Oracle JDBC驱动包

  • mybatis-3.2.4.jar
  • ojdbc6.jar

 

2)程序的搭建

首先,我们将数据源等配置信息放在一个xml,让Mybatis可以根据这个信息去连接数据库、管理事务。

目前我们可只关注environments节点,此节点是用于配置数据源、事务管理的 。

其他的节点,如typeAliases、mappers,是用于注册一些信息的,后面会陆续提到。

 1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4   "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5    6 <configuration> 7  8     <!-- Register Alias --> 9     <typeAliases>10         <typeAlias alias="user" type="com.nicchagil.mybatisonly.bean.User" />11     </typeAliases>12 13     <!-- Data Source -->14     <environments default="development">15         <environment id="development">16             <transactionManager type="JDBC" />17             <dataSource type="POOLED">18                 <property name="driver" value="oracle.jdbc.driver.OracleDriver" />19                 <property name="url" value="jdbc:oracle:thin:@xxx.xxx.xxx.xxx:xxxx:xxxxxx" />20                 <property name="username" value="xxxx" />21                 <property name="password" value="xxxx" />22             </dataSource>23         </environment>24     </environments>25     26     <!-- Register Mapper -->27     <mappers>28         <!-- SQL Mapper -->29         <mapper resource="com/nicchagil/mybatisonly/mapper/sqlxml/UserMapper.xml" />30     </mappers>31     32 </configuration>
mybatis-config.xml

 

既然有了配置的xml,下一步就需要让Mybatis加载它了。

  1. 首先以输入流的形式加载xml
  2. 以“SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession”的流程最后构建出SqlSession。
    • SqlSession,顾名思义,是一次会话,是应用程序与数据库交互的会话,所以,其生命周期应在一次数据库连接之间,当然,此次数据库连接可以包含一次或多次数据库操作。
    • SqlSessionFactory,顾名思义,是SqlSession的工厂类,用于产出SqlSession。我们知道,SqlSession主要用于数据库操作,而数据库操作又是贯穿于应用程序整个生命周期当中的,那么,"产出SqlSession"这个动作也应当贯穿于应用程序整个生命周期当中,所以,SqlSessionFactory的生命周期一般为应用程序的整个生命周期,一般为单例/static的形式存在。
    • SqlSessionFactoryBuilder,由代码可见,其主要作用是从配置文件中获取配置信息,然后构建SqlSessionFactory,所以其生命周期可以是临时的,局部的。
  3. 通过SqlSession获取UserMapper接口,再调用该接口的数据操纵方法。
package com.nicchagil.mybatisonly;import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.nicchagil.mybatisonly.bean.User;import com.nicchagil.mybatisonly.mapper.UserMapper;public class Call {        public static SqlSessionFactory sqlSessionFactory = null;    public static void main(String[] args) throws IOException {                // Query User        /*        kickStartMybatis();        queryUser("nick");        */                // Inser User        kickStartMybatis();        insertUser("user004", "hello world.");            }        public static void kickStartMybatis() throws IOException {        String resource = "com/nicchagil/mybatisonly/mybatis-config.xml";        InputStream inputStream = Resources.getResourceAsStream(resource);        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);    }        /**     * Query User     * @param username     * @return     */    public static User queryUser(String username) {                User user = null;        SqlSession session = sqlSessionFactory.openSession();        try {                        /* Un-recommended Method */            /*            user = (User)session.selectOne("com.nicchagil.mybatisonly.mapper.UserMapper.queryUser", username);             */                        /* Recommended Method */            UserMapper userMapper = session.getMapper(UserMapper.class);            user = userMapper.queryUser(username);                        System.out.println("username - " + user.getUsername() + " , password - " + user.getPassword());                    } finally {            session.close();        }                return user;    }        /**     * Insert User     * @param username     * @param password     */    public static void insertUser(String username, String password) {                SqlSession session = sqlSessionFactory.openSession();                try {                        UserMapper userMapper = session.getMapper(UserMapper.class);                        User user = new User();            user.setUsername(username);            user.setPassword(password);                        userMapper.insertUser(user);                        // Flushes batch statements and commits database connection.             // Note that database connection will not be committed if no updates/deletes/inserts were called.            session.commit();                        System.out.println("username - " + user.getUsername() + " , password - " + user.getPassword());                    } catch (Exception e) {            session.rollback();            e.printStackTrace();                        //TODO Print the exception logs            //TODO Prompts fail to execute for user                    } finally {            session.close();        }            }        /**     * Insert User     * @param username     * @param password     */    public static void insertUserBySQL(String username, String password) {                SqlSession session = sqlSessionFactory.openSession();                try {                        User user = new User();            user.setUsername(username);            user.setPassword(password);                        session.insert("com.nicchagil.mybatisonly.mapper.UserMapper.insertUser", user);                        // Flushes batch statements and commits database connection.             // Note that database connection will not be committed if no updates/deletes/inserts were called.            session.commit();                    } catch (Exception e) {            session.rollback();            e.printStackTrace();                        //TODO Print the exception logs            //TODO Prompts fail to execute for user                    } finally {            session.close();        }            }}
Call

 

UserMapper是一个DAO的接口,是定义作哪些数据库操作的。

1 package com.nicchagil.mybatisonly.mapper;2 3 import com.nicchagil.mybatisonly.bean.User;4 5 public interface UserMapper {6     7     public User queryUser(String username);8 9 }
UserMapper.java

 

UserMapper只是供调用的接口,那么具体的实现逻辑在哪里呢?

我们可见UserMaper.xml,它定义的SQL就是用于定义UserMapper接口的实现。我们需在mybatis-config.xml注册UserMaper.xml,可见mybatis-config.xml的mappers节点。

  • 我们可以看到id为queryUser,与接口的方法名对应;
  • SQL我们很熟悉了,就是一个简单的SQL,而#{username},就是接口方法的入参;
  • resultType为"user",这个user是一个别名,具体对应com.nicchagil.mybatisonly.bean.User这个类,我们可以看到在mybatis-config.xml文件的typeAliases节点中已经注册它们的映射关系。
<?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.nicchagil.mybatisonly.mapper.UserMapper">    <select id="queryUser" resultType="user">        select * from t_user_test_1407 t where t.username = #{username}    </select>        <insert id="insertUser" parameterType="user">        INSERT INTO t_user_test_1407 T (T.USERNAME, T.PASSWORD) VALUES (#{username}, #{password})    </insert></mapper>
UserMapper.xml

 

而com.nicchagil.mybatisonly.bean.User是实体类,用于装载数据。

 1 package com.nicchagil.mybatisonly.bean; 2  3 public class User { 4  5     private String username; 6     private String password; 7  8     public String getUsername() { 9         return username;10     }11 12     public void setUsername(String username) {13         this.username = username;14     }15 16     public String getPassword() {17         return password;18     }19 20     public void setPassword(String password) {21         this.password = password;22     }23 24     @Override25     public int hashCode() {26         final int prime = 31;27         int result = 1;28         result = prime * result29                 + ((password == null) ? 0 : password.hashCode());30         result = prime * result31                 + ((username == null) ? 0 : username.hashCode());32         return result;33     }34 35     @Override36     public boolean equals(Object obj) {37         if (this == obj)38             return true;39         if (obj == null)40             return false;41         if (getClass() != obj.getClass())42             return false;43         User other = (User) obj;44         if (password == null) {45             if (other.password != null)46                 return false;47         } else if (!password.equals(other.password))48             return false;49         if (username == null) {50             if (other.username != null)51                 return false;52         } else if (!username.equals(other.username))53             return false;54         return true;55     }56 57 }
User.java

 

最后,我们运行Call.java,将能成功查询、插入数据库。我们可通过打印的信息和查询数据库,以查看是否成功查询、插入数据。

 

3)事务说明

对于数据库有写操作的应用程序,一般来说,事务是不可或缺的一部分。因为未使用其他框架,这里使用编程式事务,即使用SqlSession.commit()和SqlSession.rollback()方法,可见Call.java。

  • 由于本程序对事务有异常回滚的要求,所以,需要获取非自动提交的SqlSession
  • 如程序执行正常,则最后执行session.commit()以提交事务。
    • session.commit()有个需注意的地方,参考其如下注释,即如果当前会话中不涉及updates/deletes/insert等写数动作则不提交事务。所以,如果要触发Mybatis提交事务,就需执行明确的触发动作,如“执行session.insert(...)方法”或“执行对应的SQL Mapper配置中的insert、update、delete等标签”等操作。(本人曾尝试在SQL Mapper配置中用select标签包含INSERT的SQL,使用SqlSession.commit()后,执行正常,但没有提交事务,可见并未触发,所以,需规范使用标签)。如需强制提交,可用SqlSession.commit(boolean)。

      Flushes batch statements and commits database connection. Note that database connection will not be committed if no updates/deletes/inserts were called. To force the commit call SqlSession.commit(boolean)

  • 如程序执行异常,则回滚事务,session.rollback()

 

单独搭建Mybaits完毕!

 

二、 Mybatis与Spring的整合

一个项目中,单独使用Mybatis的情况并不多;更多的情况下,我们需要将Mybatis与其他框架进行整合,以便更好地使用。比如Mybatis + Spring,就是一个流行的整合组合。

 

1)环境准备、版本说明

本次用Mybatis3 + Spring3进行整合。注意,并不包含MVC框架的配置,因为本文的目的是学习Mybatis,所以尽量不引用其他框架,以避免影响代码的理解。

需引入的类库详情如下:

<dependencies>      <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>3.8.1</version>      <scope>test</scope>    </dependency>        <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context</artifactId>        <version>3.2.10.RELEASE</version>    </dependency>        <dependency>        <groupId>org.springframework.webflow</groupId>        <artifactId>spring-webflow</artifactId>        <version>2.4.0.RELEASE</version>    </dependency>        <dependency>        <groupId>org.springframework.data</groupId>        <artifactId>spring-data-oracle</artifactId>        <version>1.0.0.RELEASE</version>    </dependency>        <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis</artifactId>      <version>3.2.4</version>    </dependency>        <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis-spring</artifactId>      <version>1.2.2</version>    </dependency>  </dependencies>
MVN dependencies

 

2)程序的搭建

首先,我们在Spring中配置关于Mybatis数据源的信息。

这里以applicationContext-mybatis.xml来体现,配置了如下信息:

  • 注册数据源,常见的有JDBC或JNDI,根据具体情况择一。
  • 注册sqlSessionFactory
    • sqlSessionFactory是用来生产sqlSession以操作数据库的,所以,需指定sqlSessionFactory所引用的数据源
    • 指定相应的SQL Mapper文件在哪里。我们自命名“_mapper后缀的xml文件”,主要用来定义SQL;“_resultmap后缀的xml文件”,则主要用来定义DB字段与应用程序实体属性的映射。
    • 指定相应的应用程序实体在哪里,并自动注册不包含package名的别名
  • 在哪些package下扫描Mapper接口,即DAO接口
<?xml version="1.0" encoding="UTF-8"?><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-3.0.xsd    http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.0.xsd">    <!-- JDBC Data Source -->    <!--     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >        <property name="driverClassName" value="http://www.mamicode.com/oracle.jdbc.driver.OracleDriver" />        <property name="url"            value="http://www.mamicode.com/jdbc:oracle:thin:@hostname:port:sid" />        <property name="username" value="http://www.mamicode.com/username" />        <property name="password" value="http://www.mamicode.com/password" />    </bean>    -->        <!-- JNDI Data Source -->    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">        <property name="jndiName">            <value>JNDI_TEST_DB</value>        </property>    </bean>    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="dataSource" />        <property name="mapperLocations">            <list>                <value>classpath:com/nicchagil/mybatis3spring3intg/mapper/sqlxml/*_mapper.xml</value>                <value>classpath:com/nicchagil/mybatis3spring3intg/bean/resultmapxml/*_resultmap.xml</value>            </list>        </property>        <property name="typeAliasesPackage" value="com.nicchagil.mybatis3spring3intg.bean" />    </bean>    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">        <property name="basePackage" value="com.nicchagil.mybatis3spring3intg.mapper" />        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />    </bean></beans>
applicationContext-mybatis.xml

 

 

除了Mybatis的信息,还有一些Spring的信息需要配置:

  • 根据注解自动扫描并注册bean
  • Spring的声明式事务管理(用以替代上一章节的“编程式事务”)
  • 由于本程序没有集成MVC框架,在Servlet是通过Spring编程式地获得Spring管理的bean,所以这里注册一个Spring的工具类。(使用了MVC框架并将框架交由Spring IOC容器管理的,可忽视此点配置)
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:tx="http://www.springframework.org/schema/tx"    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-3.0.xsd    http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.0.xsd    http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">    <context:component-scan base-package="com.nicchagil.mybatis3spring3intg" />        <!-- Transaction Support -->    <tx:annotation-driven transaction-manager="transactionManager" />    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" />    </bean>        <bean id="SpringContextUtil" class="com.nicchagil.util.SpringContextUtil"/></beans>
applicationContext.xml

 

 

众所周知,以上是Spring的配置文件,那么我们需要告诉应用程序“这些配置文件在哪里”,所以我们需要在web.xml中告诉应用程序。另外,此web.xml注册了一个Servlet,用于接收页面的请求。

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">  <display-name>mybatis3spring3Intg</display-name>  <welcome-file-list>    <welcome-file>index.html</welcome-file>  </welcome-file-list>  <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener>  <context-param>    <param-name>contextConfigLocation</param-name>    <param-value>classpath*:config/applicationContext*.xml</param-value>  </context-param>  <servlet>    <description></description>    <display-name>UserServlet</display-name>    <servlet-name>UserServlet</servlet-name>    <servlet-class>com.nicchagil.mybatis3spring3intg.servlet.UserServlet</servlet-class>  </servlet>  <servlet-mapping>    <servlet-name>UserServlet</servlet-name>    <url-pattern>/UserServlet</url-pattern>  </servlet-mapping></web-app>
web.xml

 

我们还需要定义Mapper的接口,即DAO接口。此处的Mapper的接口,我们已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描。

package com.nicchagil.mybatis3spring3intg.mapper;import com.nicchagil.mybatis3spring3intg.bean.User;public interface UserMapper {        public User find(String username);        public void save(User user);}
UserMapper.java

 

而Mapper的实现是如何的呢?

Mybatis会帮我们实现,我们只需要通过user_mapper.xml文件告诉Mybatis对应的SQL,此处的mapper文件,已经在applicationContext-mybatis.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.nicchagil.mybatis3spring3intg.mapper.UserMapper">    <select id="find" resultType="user" resultMap="userResultMap">        select * from t_user_test_1407 t where t.username = #{username}    </select>        <insert id="save" parameterType="user">        INSERT INTO t_user_test_1407 T (T.USERNAME, T.PASSWORD) VALUES (#{username}, #{password})    </insert></mapper>
user_mapper.xml

 

可以看到,Mapper和SQL配置文件中都引用到了实体类,我们也需要定义。此处的实体类,已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描。

package com.nicchagil.mybatis3spring3intg.bean;public class User {    private String username;    private String password;    private String childhoodName;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String getChildhoodName() {        return childhoodName;    }    public void setChildhoodName(String childhoodName) {        this.childhoodName = childhoodName;    }    @Override    public int hashCode() {        final int prime = 31;        int result = 1;        result = prime * result                + ((childhoodName == null) ? 0 : childhoodName.hashCode());        result = prime * result                + ((password == null) ? 0 : password.hashCode());        result = prime * result                + ((username == null) ? 0 : username.hashCode());        return result;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        User other = (User) obj;        if (childhoodName == null) {            if (other.childhoodName != null)                return false;        } else if (!childhoodName.equals(other.childhoodName))            return false;        if (password == null) {            if (other.password != null)                return false;        } else if (!password.equals(other.password))            return false;        if (username == null) {            if (other.username != null)                return false;        } else if (!username.equals(other.username))            return false;        return true;    }}
User.java

 

实体的属性与DB的字段之间的映射/匹配,我们需要定义一下。此处的resultmap.xml文件已经在applicationContext-mybatis.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.nicchagil.mybatis3spring3intg.mapper.UserMapper">    <resultMap type="user" id="userResultMap">        <result property="username" column="USERNAME" />        <result property="password" column="PASSWORD" />        <result property="childhoodName" column="USERNAME" />    </resultMap></mapper>
user_resultmap.xml

 

完成了DAO,那么接着写Service。

首先一个Service的接口。

package com.nicchagil.mybatis3spring3intg.service;import com.nicchagil.mybatis3spring3intg.bean.User;public interface UserService {        public User query(String username);        public void save(User user);        public void testTransaction(User user1, User user2);}
UserService.java

 

Service的实现类如下,这里只简单地测试查询、保存、事务是否能正常处理。

 

package com.nicchagil.mybatis3spring3intg.service.impl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import com.nicchagil.mybatis3spring3intg.bean.User;import com.nicchagil.mybatis3spring3intg.mapper.UserMapper;import com.nicchagil.mybatis3spring3intg.service.UserService;@Servicepublic class UserServiceImpl implements UserService {        @Autowired    private UserMapper mapper;        @Override    public User query(String username) {        return mapper.find(username);    }        @Override    public void save(User user) {        mapper.save(user);    }    @Override    @Transactional    public void testTransaction(User user1, User user2) {        mapper.save(user1);                // Code a NullPointerException to test transaction setting        String str = null;        str.charAt(0);                mapper.save(user2);    }    }
UserServiceImpl.java

 

由于没有整合MVC框架,此处由一个Servlet(此Servlet已于web.xml中注册)获取页面请求并调用Service,

那么如何在Servlet中获得Spring IOC管理下Service的bean呢?这里借助SpringContextUtil(implements ApplicationContextAware),此SpringContextUtil于以上提及的applicationContext.xml中注册。

package com.nicchagil.mybatis3spring3intg.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.nicchagil.mybatis3spring3intg.bean.User;import com.nicchagil.mybatis3spring3intg.service.UserService;import com.nicchagil.util.SpringContextUtil;/** * Servlet implementation class UserServlet */public class UserServlet extends HttpServlet {    private static final long serialVersionUID = 1L;           /**     * @see HttpServlet#HttpServlet()     */    public UserServlet() {        super();        // TODO Auto-generated constructor stub    }    /**     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)     */    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        this.doPost(request, response);    }    /**     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)     */    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {                String action = request.getParameter("action");                UserService service = (UserService)SpringContextUtil.getBean("userServiceImpl");                if ("find".equals(action)) {            User user = service.query(request.getParameter("username"));            System.out.println(user.getUsername() + " - " + user.getPassword() + " - " + user.getChildhoodName());                    }                if ("save".equals(action)) {            User user = new User();            user.setUsername(request.getParameter("username"));            user.setPassword(request.getParameter("password"));                        service.save(user);            System.out.println(user.getUsername() + " - " + user.getPassword());                    }                if ("testTransaction".equals(action)) {            User user1 = new User();            user1.setUsername(request.getParameter("username"));            user1.setPassword(request.getParameter("password"));                        User user2 = new User();            user2.setUsername(request.getParameter("username") + " - Double");            user2.setPassword(request.getParameter("password") + " - Double");                        service.testTransaction(user1, user2);            System.out.println(user1.getUsername() + " - " + user1.getPassword());            System.out.println(user2.getUsername() + " - " + user2.getPassword());                    }            }}
UserServlet.java

 

package com.nicchagil.util;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;public class SpringContextUtil implements ApplicationContextAware {        private static ApplicationContext applicationContext = null;    @Override    public void setApplicationContext(ApplicationContext ac)            throws BeansException {        applicationContext = ac;    }    public static ApplicationContext getApplicationContext() {        return applicationContext;    }        public static Object getBean(String beanName) {        return applicationContext.getBean(beanName);    }        public static boolean containsBean(String beanName) {        return applicationContext.containsBean(beanName);    }}
SpringContextUtil.java

 

 

几乎大功告成。

这里写了些触发测试的页面,执行结果可通过“查看控制台”或“查询数据库”获得。哈哈!~~

导航页

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Insert title here</title></head><body><a href="find.html">find</a><br/><a href="save.html">save</a><br/><a href="testTransaction.html">testTransaction</a></body></html>
index.html

 

输入username查询记录的触发页面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Insert title here</title></head><body>    <form action="UserServlet">        <input type="hidden" name="action" value="find">        <input type="text" name="username">        <input type="submit">    </form></body></html>
find.html

 

保存页面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Insert title here</title></head><body><body>    <form action="UserServlet">        <input type="hidden" name="action" value="save">        <input type="text" name="username">         <input type="password" name="password">         <input type="submit">    </form></body></body></html>
save.html

 

测试事务的触发页面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Insert title here</title></head><body><body>    <form action="UserServlet">        <input type="hidden" name="action" value="testTransaction">        <input type="text" name="username">         <input type="password" name="password">         <input type="submit">    </form></body></body></html>
testTransaction.html

 

大功告成!!