spring + springmvc + mybatis整合记录,外加spring transaction

整合不是什么难事,配置文件照葫芦画瓢总能出来。关键是transaction有问题,总是不能够完成事务。

环境:eclipse for javaee , maven , jdk1.8

 依赖的jar包

有一部分不是必须的,比如jackson那个是配合spring返回json串用的,

还比如common-fileupload是用来配合spring上传文件用的。自行进行取舍。

但是这里还是要提一下 ,由于spring transaction(事务)是基于aop实现的,所以也需要aopalliance的jar包。(从别的博文习得的知识)

配置流程

1.常规建立maven项目,并将web-content放置在main/webapp下。

pom.xml和文件目录

文件没有独立建包。看得懂就行。

除pom.xml配置外的,其他依赖的包都是通过maven自动添加。 

2.配置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"
	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">

	<!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- 前端控制器The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>	
	
	</web-app>

 Tip:contextConfigLocation、contextLoaderListener和springDispatcherServlet,在eclipse中通过在空白区域按下,alt+/ ,自动生成,前提是eclipse已经装好了相关的spring插件。

另外,spring配置文件如果不是名为applicationContext.xml的话,就需要在web.xml中使用<context-param>和<listener>指定加载。(别的文章看的,我没有验证过)

3.配置springmvc.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:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		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/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
		
	<!--配置视图解析器-->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	<!-- 配置CommonsMultipartResolver,文件的上传 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="defaultEncoding" value="utf-8"></property>
	</bean>
	<!--这是Spring MVC为@Controller分发请求所必需的-->
	<mvc:annotation-driven></mvc:annotation-driven>
        <!-- 找不到映射,就访问相应的资源 -->
	<mvc:default-servlet-handler/>
</beans>

 4.配置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: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-4.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	<!-- 指定spring要扫描的包 -->
	<context:component-scan base-package="com.maven.spring"></context:component-scan>
	<!-- 导入jdbc.properties  -->
	<context:property-placeholder location="jdbc.properties"/>
	<!-- c3p0数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="initialPoolSize" value="10"></property>
		<property name="acquireIncrement" value="5"></property>
		<property name="minPoolSize" value="5"></property>
		<property name="maxPoolSize" value="20"></property>
	 </bean>	 
	 
	 <!-- spring整合 mybatis -->
	 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	 	<property name="dataSource" ref="dataSource"></property>
	 	<property name="mapperLocations" value="classpath*:com/maven/spring/transaction/*.xml"></property>
	 </bean>
	 <!-- 自动扫描对象关系映射 ,DAO接口所在包名,Spring会自动查找其下的类 -->
	 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	 	<!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
	 	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	 	<!-- 指定要自动扫描接口的基础包,实现接口 -->
	 	<property name="basePackage" value="com.maven.spring.transaction"></property>
	 </bean>
	<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!-- 启动@Transactional注解 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
	
</beans>

 5.mapper与dao(省略pojo对象)

mapper.java 

package com.maven.spring.transaction;

import org.apache.ibatis.annotations.Param;

public interface DepositMapper {
	public double getMoney(int id);
	public void moneyOut(@Param("id") int id,@Param("money")double money);
	public void moneyIn(@Param("id")int id,@Param("money")double money);
	
}

 mybatis 在传入多个参数时使用@Param标记,使得在对应xml文件中能以#{id},#{money}区分,否则默认为#{arg0},#[arg1}或者#{0},#{1},详情:MyBatis传入多个参数的问题

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.maven.spring.transaction.DepositMapper">
  	<resultMap type="com.maven.spring.transaction.Deposit" id="BaseResultMap">
  		<result column="user_name" property="userName"/>
  	</resultMap>
  		<select id="getMoney" resultType="java.lang.Double">
  			SELECT money FROM test_deposit WHERE id=#{id}
  		</select>
  		<update id="moneyOut" >
  			UPDATE test_deposit SET money = money-#{money} WHERE id=#{id}
  		</update>
  		<update id="moneyIn" >
  			UPDATE test_deposit SET money = money+#{money} WHERE id=#{id}
  		</update>
  </mapper>

 6.daoimpl

package com.maven.spring.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class DepositDao {
	
	@Autowired
	private DepositMapper depositMapper=null;
	//存钱
	public void moneyIn(int id,double money) {
		depositMapper.moneyIn(id, money);
		System.out.println("money in");
	}
	//取钱
	public void moneyOut(int id,double money) {
		double restMoney = depositMapper.getMoney(id);//获得账户余额
		if(restMoney > money) {//比较账户余额和所需要取出的量
			depositMapper.moneyOut(id, money);
			System.out.println("money out"); //控制台输出,测试用
		}else {
			throw new NotEnoughMoneyException("余额不足!");
		}
	}
}

这个文件的作用就是在取钱的时候,比较剩余的钱,然后手动抛出异常。(可以根据情况取舍)

因为不抛出异常的话,transaction事务会无法正常运行,或者说回滚。

这个异常是自定义异常类,继承自RuntimeException,重写了构造方法。 

7.service层

package com.maven.spring.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class DepositService {
	
	@Autowired
	private DepositDao depositDao;
	//添加事务注解
	@Transactional
	public void transferAccountsTransaction() {
		depositDao.moneyIn(1, 300);//在账户1加300
		depositDao.moneyOut(2, 300);//在账户2减去300
	}
}

 完成“转账”的功能,故意先将钱加给用户1,在再向用户2扣钱,使异常发生在第二步moneyOut,观察事务是否回滚。

 8.测试层(就当成是controller层看吧。。)

package com.maven.spring.transaction;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTranscation {
	
	DepositService depositService = null;
	ApplicationContext ctx=null;
	{
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		depositService = ctx.getBean(DepositService.class);
	}
	@Test
	public void test() {
		System.out.println("do transaction");
		depositService.transferAccountsTransaction();
	}
}

如果配置正常,在eclipse上会有提示

这个标记和aop的标记是一样的,这更加验证了spring transaction的底层仍然是aop

结果

运行成功,由于数据库用户2(id=2)余额只有200,而我想要取出300元,所以抛出了余额不足的异常。transaction事务回滚,用户1(id =1)的钱没有加上。

 

附上数据库:

 

收获:

作为spring初学者:

	ApplicationContext ctx=null;
	{
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		depositMapper = ctx.getBean(DepositMapper.class);
	}

通过这种方式获得的bean,和@autowired自动获得的bean,应该是差不多的,细节还不了解,只知道注解方式在用JUnit单元测试的时候会报空指针异常,且使用注解方式获得bean一定要在目标方法上加上@Service/@Repository/@Component等注解,使配置文件通过component-scan扫描进去才行。

如果稍微在配置的地方将<context:component-scan>扫描包的时候放错放错位置,到springmvc.xml的时候,可能会报java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException,在配置中就因为对spring不够了解,出现了很多次这个异常。而在百度上,相当一部分结果认为这个异常是因为jvm内存太小,我这种小程序怎么能和jvm内存扯上关系呢,果断放弃。直到看见一些大牛说,spring<bean>的重复配置可能会导致这个问题。

 

 

 这篇文章仅代表我的个人的看法,所述观点不一定都对,毕竟对于javaweb要学习的还有很多。希望本文能给予您灵感。

参考文献: 

mvc:annotation-driven注解的作用

SpringMVC+Spring+mybatis项目从零开始--Spring mybatis mysql配置实现(这个还是挺详细的)

Spring集成MyBatis完整示例

@autowired 注入失败

spring+springmvc+mybatis事务失效问题

SpringMvc和Mybatis整合需要配置的xml

SpringMVC+MyBatis 事务中 基于注解的声明式事务

浅谈web.xml文件中加载Spring配置文件和SpringMVC配置文件

浅谈配置文件:spring-servlet.xml(spring-mvc.xml) 与 applicationContext.xml(交代了springmvc和spring之间配置文件的关系)

Maven项目引入log4j的详细配置

MyBatis传入多个参数的问题 (mybatis基础)

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值