zoukankan      html  css  js  c++  java
  • 由“单独搭建Mybatis”到“Mybatis与Spring的整合/集成”

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

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

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

    不喜欢的是:

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

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

    一、数据库的准备

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

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

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


    insert into T_USER_TEST_1407 (USERNAME, PASSWORD)
    values ('nick', 'Optimistic,Confident,Love - 1');


    insert into T_USER_TEST_1407 (USERNAME, PASSWORD)
    values ('nick', 'Optimistic,Confident,Love - 1');

    二、单独搭建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,是用于注册一些信息的,后面会陆续提到。

    mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">

    <configuration>

    <!-- Register Alias -->
    <typeAliases>
    <typeAlias alias="user" type="com.nicchagil.mybatisonly.bean.User" />
    </typeAliases>

    <!-- Data Source -->
    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC" />
    <dataSource type="POOLED">
    <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@xxx.xxx.xxx.xxx:xxxx:xxxxxx" />
    <property name="username" value="xxxx" />
    <property name="password" value="xxxx" />
    </dataSource>
    </environment>
    </environments>

    <!-- Register Mapper -->
    <mappers>
    <!-- SQL Mapper -->
    <mapper resource="com/nicchagil/mybatisonly/mapper/sqlxml/UserMapper.xml" />
    </mappers>

    </configuration>

    mybatis-config.xml


    复制代码
     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>
    复制代码

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

    1. 首先以输入流的形式加载xml
    2. 以“SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession”的流程最后构建出SqlSession。
      • SqlSession,顾名思义,是一次会话,是应用程序与数据库交互的会话,所以,其生命周期应在一次数据库连接之间,当然,此次数据库连接可以包含一次或多次数据库操作。
      • SqlSessionFactory,顾名思义,是SqlSession的工厂类,用于产出SqlSession。我们知道,SqlSession主要用于数据库操作,而数据库操作又是贯穿于应用程序整个生命周期当中的,那么,"产出SqlSession"这个动作也应当贯穿于应用程序整个生命周期当中,所以,SqlSessionFactory的生命周期一般为应用程序的整个生命周期,一般为单例/static的形式存在。
      • SqlSessionFactoryBuilder,由代码可见,其主要作用是从配置文件中获取配置信息,然后构建SqlSessionFactory,所以其生命周期可以是临时的,局部的。
    3. 通过SqlSession获取UserMapper接口,再调用该接口的数据操纵方法。
    Call

    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


    复制代码
    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();
            }
            
        }
    
    }
    复制代码

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

    UserMapper.java

    package com.nicchagil.mybatisonly.mapper;

    import com.nicchagil.mybatisonly.bean.User;

    public interface UserMapper {

    public User queryUser(String username);

    }


    复制代码
    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只是供调用的接口,那么具体的实现逻辑在哪里呢?

    我们可见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节点中已经注册它们的映射关系。
    UserMapper.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.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


    复制代码
    <?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>
    复制代码

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

    User.java

    package com.nicchagil.mybatisonly.bean;

    public class User {

    private String username;
    private String password;

    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;
    }

    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    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 (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


    复制代码
     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     @Override
    25     public int hashCode() {
    26         final int prime = 31;
    27         int result = 1;
    28         result = prime * result
    29                 + ((password == null) ? 0 : password.hashCode());
    30         result = prime * result
    31                 + ((username == null) ? 0 : username.hashCode());
    32         return result;
    33     }
    34 
    35     @Override
    36     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 }
    复制代码

    最后,我们运行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,所以尽量不引用其他框架,以避免影响代码的理解。

    需引入的类库详情如下:

    MVN dependencies

    <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>


    复制代码
    <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>
    复制代码

    2)程序的搭建

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

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

    • 注册数据源,常见的有JDBC或JNDI,根据具体情况择一。
    • 注册sqlSessionFactory
      • sqlSessionFactory是用来生产sqlSession以操作数据库的,所以,需指定sqlSessionFactory所引用的数据源
      • 指定相应的SQL Mapper文件在哪里。我们自命名“_mapper后缀的xml文件”,主要用来定义SQL;“_resultmap后缀的xml文件”,则主要用来定义DB字段与应用程序实体属性的映射。
      • 指定相应的应用程序实体在哪里,并自动注册不包含package名的别名
    • 在哪些package下扫描Mapper接口,即DAO接口
    applicationContext-mybatis.xml

    <?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="oracle.jdbc.driver.OracleDriver" />
    <property name="url"
    value="jdbc:oracle:thin:@hostname:port:sid" />
    <property name="username" value="username" />
    <property name="password" value="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


    复制代码
    <?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="oracle.jdbc.driver.OracleDriver" />
            <property name="url"
                value="jdbc:oracle:thin:@hostname:port:sid" />
            <property name="username" value="username" />
            <property name="password" value="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>
    复制代码

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

    • 根据注解自动扫描并注册bean
    • Spring的声明式事务管理(用以替代上一章节的“编程式事务”)
    • 由于本程序没有集成MVC框架,在Servlet是通过Spring编程式地获得Spring管理的bean,所以这里注册一个Spring的工具类。(使用了MVC框架并将框架交由Spring IOC容器管理的,可忽视此点配置)
    applicationContext.xml

    <?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


    复制代码
    <?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>
    复制代码

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

    web.xml

    <?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


    复制代码
    <?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>
    复制代码

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

    UserMapper.java

    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


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

    而Mapper的实现是如何的呢?

    Mybatis会帮我们实现,我们只需要通过user_mapper.xml文件告诉Mybatis对应的SQL,此处的mapper文件,已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描

     user_mapper.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>
    复制代码

    复制代码
    <?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>
    复制代码

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

    User.java

    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


    复制代码
    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;
        }
    
    }
    复制代码

    实体的属性与DB的字段之间的映射/匹配,我们需要定义一下。此处的resultmap.xml文件已经在applicationContext-mybatis.xml中注册为指定路径下自动扫描

    user_resultmap.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


    复制代码
    <?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>
    复制代码

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

    首先一个Service的接口。

    UserService.java

    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


    复制代码
    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);
    
    }
    复制代码

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

     UserServiceImpl.java

    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;

    @Service
    public 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中注册

    UserServlet.java

    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.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());
                
            }
            
        }
    
    }
    复制代码
    SpringContextUtil.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


    复制代码
    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);
        }
    
    }
    复制代码

    几乎大功告成。

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

    导航页

    index.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>

    <a href="find.html">find</a>
    <br/>
    <a href="save.html">save</a>
    <br/>
    <a href="testTransaction.html">testTransaction</a>

    </body>
    </html>

    index.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>
    
    <a href="find.html">find</a>
    <br/>
    <a href="save.html">save</a>
    <br/>
    <a href="testTransaction.html">testTransaction</a>
    
    </body>
    </html>
    复制代码

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

    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>

    <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>
    
        <form action="UserServlet">
            <input type="hidden" name="action" value="find">
            <input type="text" name="username">
            <input type="submit">
        </form>
    
    </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="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="save">
            <input type="text" name="username"> 
            <input type="password" name="password"> 
            <input type="submit">
        </form>
    
    </body>
    
    </body>
    </html>
    复制代码

    测试事务的触发页面

    testTransaction.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


    复制代码
    <!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>
    复制代码

    大功告成!!

     分享于:

    https://github.com/nicchagil/mybatis3spring3Intg/tree/mybatis3spring3Intg_branch_initialization

  • 相关阅读:
    php面试题8
    mysql分区功能(三个文件储存一张表)(分区作用)(分区方式)
    iconv简介(1、字符串|文件字符转换:iconv用于将一种已知的字符集文件转换成另一种已知的字符集文件)(2、编程语言函数功能的相似性:iconv不仅再php中有用,而且c语言中也有用,还有linux等)
    php面试题7(1、unset变量是删除栈变量,并不删除堆变量)(2、php爬虫特别简单: 可以file_get_contents和直接fopen)
    为什么位运算可以实现加法(1、 不考虑进位的情况下位运算符中的异或^可以表示+号)(2、 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3、位运算不仅可以做加法,还可以做其它的乘法减法等:计算机本质是二进制运算)
    php实现不用加减乘除号做加法(1、善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍)
    php求二叉树的深度(1、二叉树就可以递归,因为结构和子结构太相似)(2、谋而后动,算法想清楚,很好过的)
    ajax实现注册用户名时动态显示用户名是否已经被注册(1、ajax可以实现我们常见的注册用户名动态判断)(2、jquery里面的ajax也是类似我们这样封装了的函数)
    HDU 4513 哥几个系列故事——形成完善II manacher求最长回文
    设计模式模式游客(Visitor)摘录
  • 原文地址:https://www.cnblogs.com/telwanggs/p/5403165.html
Copyright © 2011-2022 走看看