今天发现一个奇怪的问题,Spring2.5的事物处理过程中,在web中事物控制无效,但是利用ClassPathXmlApplicationContext加载bean的方式可以进行事物控制。Web的代码如下:
/WEB-INF/SpringDemo-servlet.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- ①:对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
<context:component-scan
base-package="com.example.springdemo"/>
<!-- ②:启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!-- ③:对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp"/>
</beans>
Classpath:
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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config
/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost/springdemo" />
<property name="username"
value="root" />
<property name="password"
value="sa" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"
ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager"
proxy-target-class="true"/>
<!--
利用ClassPathXmlApplicationContext方式加载时需要打开注释
<context:component-scan
base-package="com.example.springdemo"/>
-->
</beans>
log4j.properties
log4j.rootLogger=INFO, A1 , R
log4j.logger.org.apache=INFO
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}
[%c]-[%p] %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=C:/OSWorkflowDemo.log
log4j.appender.R.MaxFileSize=1000KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
测试的java函数:
public static void
main(String[] args) {
// TODO
Auto-generated method stub
String [] conf = new
String[2];
conf[0]="applicationContext.xml";
conf[1]="dataAccessContext-jdbc.xml";
ApplicationContext
appContext = new ClassPathXmlApplicationContext(conf);
UserService us =
(UserService) appContext.getBean("userService");
us.testTx();
// System.out.println("hello");
}
其他java类的主要函数如下:
public interface UserService {
void testTx();
}
@Service("userService")
public class UserServiceImpl implements
UserService{
@Autowired
@Qualifier("userDao")
private UserDAO
userDao;
public void
testTx() {
userDao.insertTwoRecord();
}
}
public interface UserDAO {
void insertTwoRecord();
}
@Component("userDao")
@Transactional
public class UserDAOImpl implements UserDAO{
private JdbcTemplate
jdbcTemplate;
@Autowired
public void
setDataSource(@Qualifier("dataSource")DataSource dataSource) {
this.jdbcTemplate = new
JdbcTemplate(dataSource);
}
@Transactional(readOnly=false)
public void
insertTwoRecord() {
System.out.println("hello
");
jdbcTemplate.execute("INSERT
INTO USER(USERNAME,PASSWORD,EMAIL)VALUES('123','123','123')");
jdbcTemplate.execute("INSERT
INTO USER(USERNAME,PASSWORD,EMAIL)VALUES('12322222222222222222','123','123')");
}
}
@Controller
public class HelloController {
@Autowired
@Qualifier("userService")
private UserService
userService;
@RequestMapping("/sayHello.do")
public String
sayHello(ModelMap map,@RequestParam("id") Long userId){
map.put("username",
"sayHello 1 ");
userService.testTx();
return
"sayHello";
}
@RequestMapping("/sayHello2.do")
public String
sayHello2(ModelMap map,@RequestParam("name") String username){
map.put("username",
username);
return
"sayHello";
}
}
数据库的脚本如下:
CREATE TABLE `user` (
`ID` int(11) NOT NULL
auto_increment,
`PASSWORD` varchar(10) default
NULL,
`USERNAME` varchar(16) NOT NULL,
`EMAIL` varchar(64) default NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Web.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- Spring 服务层的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml,classpath:dataAccessContext-jdbc.xml</param-value>
</context-param>
<!-- Spring 容器启动监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Spring MVC 的Servlet,它将加载WEB-INF/annomvc-servlet.xml
的
配置文件,以启动Spring MVC模块-->
<servlet>
<servlet-name>SpringDemo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringDemo</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
其中,dataAccessContext-jdbc.xml是个空文件,上面的配置没有列出。在上面的代码测试过程中,遇到了不少的问题,下面进行简单的列举。
1、关于beans里面的xmlns=http://www.springframework.org/schema/beans错误,总是在提示出现错误。发现是lib下面的spring的jar包存在不同的版本,删除jar包后重新加入一个spring的包后好了。
2、后来出现了一个问题,错误提示信息没有记下,反正在网上也是找到了解决的办法。错误的原因是利用myeclipse加入了hibernate和spring的jar包,其中,asm系列的包有冲突,删除之后好了。
3、利用ClassPathXmlApplicationContext方式加载时需要加入
context:component-scan ,不然不能识别bean,并且在SpringDemo-servlet.xml文件中,必须有上面xml文件中的1,2,3.否则的话web模式下请求的url不被识别。
4、最后一个问题还是最要命的,就是两种bean的加载模式下,事物控制有效和无效。网上有人提出:估计spring初始化时优先component-scan bean,注入Web Controller 的Service直接拿了上下文中的@Service("someService"),这个时候@Transactional (readOnly=false, isolation =
Isolation.READ_COMMITTED) 还没有被处理.所以Web
Controller 的Service是SomeServiceImpl而不是AOP的$ProxyNO。提出的解决办法是:不让spring扫描到ServiceImpl类,直接写在xml文件,其它的配置和annotation照用,这样事务就起作用了。这样可以,但是service就必须写在xml文件里面了。感觉不爽。