今天發現一個奇怪的問題,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文件里面了。感覺不爽。