- 浏览: 23043 次
- 性别:
- 来自: 上海
最新评论
java笔记:自己动手写javaEE框架(五)--Spring事务管理学习
上篇文章写到了编程式事务的使用TransactionTemplate类的实现,TransactionTemplate类里的execute方法需要TransactionCallback接口实现类做参数,其接口的定义中只包含一个doInTransaction方法用于执行事务操作,上面的代码中使用匿名类的方式定义TransactionCallback接口实现,并且在doInTransaction()方法中定义事务处理代码。
第五章 声明式事务管理
我们使用最多的还是Spring声明式事务管理,其实所有Spring事务管理都是基于AOP来实现,而其中的声明式事务才是真正体现AOP全部优点的最佳应用,记得我以前参加面试一说到AOP我就提及声明式事务管理,哎,那个时候对AOP的理解也就仅限于此,太菜了。Spring声明式事务不涉及组件的依赖关系,使用它时候不需要编写任何代码,很大程度的节省了工作量,提高了工作效率。下面我在我的框架里面加入声明式事务,首先修改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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <!-- 扫描该路径下的spring组件 --> <context:component-scan base-package="cn.com.sharpxiajun" /> <!-- 读取资源文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:conf/constants.properties</value> </list> </property> </bean> <!-- 配置数据源 --> <!-- <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${db.driverClass}"/> <property name="jdbcUrl" value="${db.jdbcUrl}"/> <property name="user" value="${db.user}"/> <property name="password" value="${db.password}"/> </bean>--> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${db.driverClass}"/> <property name="url" value="${db.jdbcUrl}"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.password}"/> </bean> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"> <value>classpath:conf/SqlMapConfig.xml</value> </property> <property name="dataSource" ref="myDataSource"/> </bean> <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate"> <property name="sqlMapClient"> <ref local="sqlMapClient"/> </property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="myDataSource"/> </property> </bean> <!-- 声明式事务 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true" propagation="REQUIRED"/> <tx:method name="query*" read-only="true" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="REQUIRED"/> <tx:method name="list*" read-only="true" propagation="REQUIRED"/> <tx:method name="search*" read-only="true" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="del*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="modify*" propagation="REQUIRED" isolation="READ_COMMITTED"/> </tx:attributes> </tx:advice> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="propagationBehaviorName"> <value>PROPAGATION_REQUIRED</value> </property> </bean> <!-- 将我自己定义的拦截器生成bean --> <bean id="methodServiceAdvisor" class="cn.com.sharpxiajun.common.aop.MethodServiceAdvisor"/> <aop:config> <!--配置规则,满足以下规则的将拦截,第一个*表示所有返回类型,第二个表示service包下的所有class,第三个表示所有方法--> <aop:pointcut id="baseServiceMethods" expression="execution(* cn.com.sharpxiajun.service.*.*(..))"/> <!-- 声明式事务 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="baseServiceMethods" /> <!-- 符合上面规则的拦截器都会调用到methodServiceAdvisor --> <aop:advisor advice-ref="methodServiceAdvisor" pointcut-ref="baseServiceMethods"/> </aop:config> </beans>
这里面添加了<tx:advice id="txAdvice" transaction-manager="transactionManager">,根据方法前缀不同绑定不同的事务策略,然后在<aop:config>里面添加<aop:advisor advice-ref="txAdvice" pointcut-ref="baseServiceMethods" />,那么service包下面类里的方法都会绑定相应的事务管理。在javaEE工程里面到底是DAO层绑定事务还是在Service层绑定事务?这个问题以前有同事问过我,我当时回答是都应该绑定,现在我会说最好只在Service层绑定事务。DAO层在我的理解里应该是数据库操作的映射,那是针对数据的原子操作,而Service层则是把这些各种数据库操作封装成一个业务操作单元,所以Service层的含义更符合事务本质,所以事务最好绑定在Service层。DAO层再绑定事务没必要,而且多余,甚至还会操作不必要的错误。
接下来我修改USERS.xml映射文件,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="USERS"> <select id="queryUserList" parameterClass="java.util.Map" resultClass="java.util.HashMap"> select t.username,t.password,t.enabled from users t </select> <!-- 新增用户信息 --> <insert id="addUsers" parameterClass="java.util.Map"> insert into users <dynamic prepend="("> <isNotNull prepend="," property="username"> username </isNotNull> <isNotNull prepend="," property="password"> password </isNotNull> <isNotNull prepend="," property="enabled"> enabled </isNotNull> ) </dynamic> values <dynamic prepend="("> <isNotNull prepend="," property="username"> #username:VARCHAR# </isNotNull> <isNotNull prepend="," property="password"> #password:VARCHAR# </isNotNull> <isNotNull prepend="," property="enabled"> #enabled:NUMBER# </isNotNull> ) </dynamic> </insert> </sqlMap>
修改cn.com.sharpxiajun.dao包下的接口UsersDao,代码如下:
package cn.com.sharpxiajun.dao; import java.util.List; import java.util.Map; public interface UsersDao { public static final String QUERY_USERS_SQL = "USERS.queryUserList"; public static final String ADD_USERS_SQL = "USERS.addUsers"; public List<Map<String, Object>> queryUserList(Map<String, Object> map) throws Exception; public Object addUsers(Map<String, Object> map) throws Exception; }
修改cn.com.sharpxiajun.dao.impl包下面UsersDaoImpl类,代码如下:
package cn.com.sharpxiajun.dao.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.orm.ibatis.SqlMapClientTemplate; import org.springframework.stereotype.Repository; import cn.com.sharpxiajun.dao.UsersDao; @SuppressWarnings("unchecked") @Scope("prototype") @Repository("usersDao") public class UsersDaoImpl implements UsersDao { @Autowired @Qualifier("sqlMapClientTemplate") private SqlMapClientTemplate sqlMapClientTemplate = null; public List<Map<String, Object>> queryUserList(Map<String, Object> map) throws Exception { return sqlMapClientTemplate.queryForList(QUERY_USERS_SQL, map); } @Override public Object addUsers(Map<String, Object> map) throws Exception { return sqlMapClientTemplate.insert(ADD_USERS_SQL, map); } }
修改cn.com.sharpxiajun.service包下接口UsersService,代码如下:
package cn.com.sharpxiajun.service; import java.util.List; import java.util.Map; public interface UsersService { public List<Map<String, Object>> queryUsersList(Map<String, Object> map) throws Exception; public Object addUsers(Map<String, Object> map) throws Exception; }
修改cn.com.sharpxiajun.service.impl包下类UsersServiceImpl,代码如下:
package cn.com.sharpxiajun.service.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import cn.com.sharpxiajun.dao.UsersDao; import cn.com.sharpxiajun.service.UsersService; @SuppressWarnings("unchecked") @Scope("prototype") @Service("userService") public class UsersServiceImpl implements UsersService { @Autowired @Qualifier("usersDao") private UsersDao usersDao = null; @Override public List<Map<String, Object>> queryUsersList(Map<String, Object> map) throws Exception { return usersDao.queryUserList(map); } @Override public Object addUsers(Map<String, Object> map) throws Exception { return usersDao.addUsers(map); } }
修改cn.com.sharpxiajun.junittest.service包下测试类UsersServiceImplTest,代码如下:
package cn.com.sharpxiajun.junittest.service; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.transaction.TransactionConfiguration; import cn.com.sharpxiajun.service.UsersService; import cn.com.sharpxiajun.service.impl.UsersServiceImpl; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:conf/applicationContext.xml"}) @TransactionConfiguration(defaultRollback = false) public class UsersServiceImplTest extends AbstractTransactionalJUnit4SpringContextTests { private final static Log log = LogFactory.getLog(UsersServiceImpl.class); @Autowired private UsersService usersService = null; public UsersServiceImplTest() { System.out.println("初始化测试类...."); } @Before public void setUp() throws Exception { System.out.println("测试开始...."); } @After public void tearDown() throws Exception { System.out.println("测试结束!!"); } @Test public void testQueryUserList() { Map<String, Object> map = new HashMap<String, Object>(); map.put("username", "sharpxiajun"); try { List<Map<String, Object>> list = usersService.queryUsersList(map); log.info(list); } catch (Exception e) { e.printStackTrace(); } } @Test public void testAddUsers() { Map<String, Object> map = new HashMap<String, Object>(); map.put("username", "xiajun"); map.put("password", "xiajun"); map.put("enabled", 1); try { Object obj = usersService.addUsers(map); log.info("testAddUsers:" + obj); } catch (Exception e) { e.printStackTrace(); } } }
运行测试类,结果如下:
数据新增了,但是没有体现事务的作用,我前面写事务示例代码也没有考虑到如何表现事务的作用,为了体现事务作用,我在USERS.xml配置文件里添加新方法,代码如下:
<!-- 修改用户信息 --> <update id="updateUsers" parameterClass="java.util.Map"> update users set errinfo = 'error' </update>
修改cn.com.sharpxiajun.dao包下的UsersDao接口,代码如下:
package cn.com.sharpxiajun.dao; import java.util.List; import java.util.Map; public interface UsersDao { public static final String QUERY_USERS_SQL = "USERS.queryUserList"; public static final String ADD_USERS_SQL = "USERS.addUsers"; public static final String UPDATE_USERS_SQL = "USERS.updateUsers"; public List<Map<String, Object>> queryUserList(Map<String, Object> map) throws Exception; public Object addUsers(Map<String, Object> map) throws Exception; public Object updateUsers(Map<String, Object> map) throws Exception; }
修改cn.com.sharpxiajun.dao.impl包下的UsersDaoImpl类,代码如下:
package cn.com.sharpxiajun.dao.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.orm.ibatis.SqlMapClientTemplate; import org.springframework.stereotype.Repository; import cn.com.sharpxiajun.dao.UsersDao; @SuppressWarnings("unchecked") @Scope("prototype") @Repository("usersDao") public class UsersDaoImpl implements UsersDao { @Autowired @Qualifier("sqlMapClientTemplate") private SqlMapClientTemplate sqlMapClientTemplate = null; public List<Map<String, Object>> queryUserList(Map<String, Object> map) throws Exception { return sqlMapClientTemplate.queryForList(QUERY_USERS_SQL, map); } @Override public Object addUsers(Map<String, Object> map) throws Exception { return sqlMapClientTemplate.insert(ADD_USERS_SQL, map); } @Override public Object updateUsers(Map<String, Object> map) throws Exception { return sqlMapClientTemplate.update(UPDATE_USERS_SQL, map); } }
在cn.com.sharpxiajun.service包的UsersService接口里添加方法:
public void updateUsers(Map<String, Object> map) throws Exception;
在cn.com.sharpxiajun.service.impl下的UsersServiceImpl类里实现该方法,代码如下:
@Override public void updateUsers(Map<String, Object> map) throws Exception { usersDao.addUsers(map); usersDao.updateUsers(map); }
从上面代码可以看出USERS.xml的update方法是不能被执行,程序一定会报出异常,如果方法绑定了事务,那么usersDao.addUsers(map);操作会被回滚掉,也就是新增操作不会成功,下面我在cn.com.sharpxiajun.junittest.service包下的UsersServiceImplTest类里添加新的测试方法,代码如下:
@Test public void testUpdateUsers() { Map<String, Object> map = new HashMap<String, Object>(); map.put("username", "sharp"); map.put("password", "sharp"); map.put("enabled", 1); try { usersService.updateUsers(map); } catch (Exception e) { e.printStackTrace(); } }
(注意:最好把测试新增方法的代码注释掉)
运行测试类,控制台会打印出下面异常:
2011-10-25 23:10:59 SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase] org.springframework.jdbc.BadSqlGrammarException: SqlMapClient operation; bad SQL grammar []; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in cn/com/sharpxiajun/dao/sqlmap/USERS.xml. --- The error occurred while applying a parameter map. --- Check the USERS.updateUsers-InlineParameterMap. --- Check the statement (update failed). --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'errinfo' in 'field list' at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:233) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:203) at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:378) at cn.com.sharpxiajun.dao.impl.UsersDaoImpl.updateUsers(UsersDaoImpl.java:36) at cn.com.sharpxiajun.service.impl.UsersServiceImpl.updateUsers(UsersServiceImpl.java:45) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at cn.com.sharpxiajun.common.aop.MethodServiceAdvisor.invoke(MethodServiceAdvisor.java:31) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at $Proxy18.updateUsers(Unknown Source) at cn.com.sharpxiajun.junittest.service.UsersServiceImplTest.testUpdateUsers(UsersServiceImplTest.java:103) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in cn/com/sharpxiajun/dao/sqlmap/USERS.xml. --- The error occurred while applying a parameter map. --- Check the USERS.updateUsers-InlineParameterMap. --- Check the statement (update failed). --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'errinfo' in 'field list' at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:107) at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.java:457) at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl.java:90) at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:380) at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:1) at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:200) ... 49 more Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'errinfo' in 'field list' at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.mysql.jdbc.Util.handleNewInstance(Util.java:406) at com.mysql.jdbc.Util.getInstance(Util.java:381) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1031) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3376) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3308) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1837) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1961) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2543) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1737) at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:998) at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:169) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.ibatis.common.jdbc.logging.PreparedStatementLogProxy.invoke(PreparedStatementLogProxy.java:62) at $Proxy21.execute(Unknown Source) at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java:80) at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.sqlExecuteUpdate(MappedStatement.java:216) at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:94) ... 54 more 测试结束!! 2011-10-25 23:10:59 TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@6798eb] to process 'after' execution for test: method [public void cn.com.sharpxiajun.junittest.service.UsersServiceImplTest.testUpdateUsers()], instance [cn.com.sharpxiajun.junittest.service.UsersServiceImplTest@168989e], exception [null] org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:717) at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:516) at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:291) at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:184) at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:90) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
结果如下:
没有新的记录被添加,事务被成功绑定了~~~。
那么如果我们写在Service里面的方法没有用applicationContext.xml里面设置的前缀,效果会如何了?
我在cn.com.sharpxiajun.service包的UsersService接口下添加新方法,代码如下:
public void noTransactionMethod(Map<String, Object> map) throws Exception;
在cn.com.sharpxiajun.service.impl包里UsersServiceImpl类实现该方法,代码如下:
@Override public void noTransactionMethod(Map<String, Object> map) throws Exception { usersDao.addUsers(map); usersDao.updateUsers(map); }
最后在cn.com.sharpxiajun.junittest.service包下,修改UsersServiceImplTest测试类,代码如下:
// @Test // public void testAddUsers() // { // Map<String, Object> map = new HashMap<String, Object>(); // map.put("username", "xiajun"); // map.put("password", "xiajun"); // map.put("enabled", 1); // // try { // Object obj = usersService.addUsers(map); // log.info("testAddUsers:" + obj); // } catch (Exception e) { // e.printStackTrace(); // } // } @Test public void testNoTransactionMethod() { Map<String, Object> map = new HashMap<String, Object>(); map.put("username", "sharp"); map.put("password", "sharp"); map.put("enabled", 1); try { usersService.noTransactionMethod(map); } catch (Exception e) { e.printStackTrace(); } } // @Test // public void testUpdateUsers() // { // Map<String, Object> map = new HashMap<String, Object>(); // map.put("username", "sharp"); // map.put("password", "sharp"); // map.put("enabled", 1); // // try { // usersService.updateUsers(map); // } catch (Exception e) { // e.printStackTrace(); // } // }
运行测试类,控制台打印出的异常是:
2011-10-25 23:28:00 SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase] org.springframework.jdbc.BadSqlGrammarException: SqlMapClient operation; bad SQL grammar []; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in cn/com/sharpxiajun/dao/sqlmap/USERS.xml. --- The error occurred while applying a parameter map. --- Check the USERS.updateUsers-InlineParameterMap. --- Check the statement (update failed). --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'errinfo' in 'field list' at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:233) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:203) at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:378) at cn.com.sharpxiajun.dao.impl.UsersDaoImpl.updateUsers(UsersDaoImpl.java:36) at cn.com.sharpxiajun.service.impl.UsersServiceImpl.noTransactionMethod(UsersServiceImpl.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at cn.com.sharpxiajun.common.aop.MethodServiceAdvisor.invoke(MethodServiceAdvisor.java:31) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at $Proxy18.noTransactionMethod(Unknown Source) at cn.com.sharpxiajun.junittest.service.UsersServiceImplTest.testNoTransactionMethod(UsersServiceImplTest.java:88) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in cn/com/sharpxiajun/dao/sqlmap/USERS.xml. --- The error occurred while applying a parameter map. --- Check the USERS.updateUsers-InlineParameterMap. --- Check the statement (update failed). --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'errinfo' in 'field list' at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:107) at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.java:457) at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl.java:90) at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:380) at org.springframework.orm.ibatis.SqlMapClientTemplate$9.doInSqlMapClient(SqlMapClientTemplate.java:1) at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:200) ... 49 more Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'errinfo' in 'field list' at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.mysql.jdbc.Util.handleNewInstance(Util.java:406) at com.mysql.jdbc.Util.getInstance(Util.java:381) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1031) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3376) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3308) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1837) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1961) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2543) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1737) at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:998) at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:169) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.ibatis.common.jdbc.logging.PreparedStatementLogProxy.invoke(PreparedStatementLogProxy.java:62) at $Proxy21.execute(Unknown Source) at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java:80) at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.sqlExecuteUpdate(MappedStatement.java:216) at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeUpdate(MappedStatement.java:94) ... 54 more
我们发现这里面少了事务回滚的异常,数据库查询结果如下:
有记录被新增了~~~
第六章 通过注解绑定事务管理
声明式事务咋看一下还是十分简单的,但是Spring引入注解后还有更加简单的配置,请看修改后新的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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <!-- 扫描该路径下的spring组件 --> <context:component-scan base-package="cn.com.sharpxiajun" /> <!-- 读取资源文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:conf/constants.properties</value> </list> </property> </bean> <!-- 配置数据源 --> <!-- <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${db.driverClass}"/> <property name="jdbcUrl" value="${db.jdbcUrl}"/> <property name="user" value="${db.user}"/> <property name="password" value="${db.password}"/> </bean>--> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${db.driverClass}"/> <property name="url" value="${db.jdbcUrl}"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.password}"/> </bean> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"> <value>classpath:conf/SqlMapConfig.xml</value> </property> <property name="dataSource" ref="myDataSource"/> </bean> <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate"> <property name="sqlMapClient"> <ref local="sqlMapClient"/> </property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="myDataSource"/> </property> </bean> <!-- 声明式事务 --> <!-- <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true" propagation="REQUIRED"/> <tx:method name="query*" read-only="true" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="REQUIRED"/> <tx:method name="list*" read-only="true" propagation="REQUIRED"/> <tx:method name="search*" read-only="true" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="del*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="modify*" propagation="REQUIRED" isolation="READ_COMMITTED"/> </tx:attributes> </tx:advice>--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="propagationBehaviorName"> <value>PROPAGATION_REQUIRED</value> </property> </bean> <!-- 将我自己定义的拦截器生成bean --> <bean id="methodServiceAdvisor" class="cn.com.sharpxiajun.common.aop.MethodServiceAdvisor"/> <aop:config> <!--配置规则,满足以下规则的将拦截,第一个*表示所有返回类型,第二个表示service包下的所有class,第三个表示所有方法--> <aop:pointcut id="baseServiceMethods" expression="execution(* cn.com.sharpxiajun.service.*.*(..))"/> <!-- 声明式事务 --> <!-- <aop:advisor advice-ref="txAdvice" pointcut-ref="baseServiceMethods" />--> <!-- 符合上面规则的拦截器都会调用到methodServiceAdvisor --> <aop:advisor advice-ref="methodServiceAdvisor" pointcut-ref="baseServiceMethods"/> </aop:config> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
配置文件里我把原来的声明式配置内容注释掉了,然后加入了<tx:annotation-driven transaction-manager="transactionManager"/>。
然后在cn.com.sharpxiajun.service.impl包下的UsersServiceImpl类加入@Transactional注解,代码如下:
@SuppressWarnings("unchecked") @Scope("prototype") @Transactional @Service("userService") public class UsersServiceImpl implements UsersService { ......................................................
将数据库里的数据都清除掉,运行测试类UsersServiceImplTest,测试service下的noTransactionMethod方法和updateUsers方法,结果显示数据都没有新增成功,这就说明事务绑定是成功了,这个简单吧。
总结下了:事务很重要,我希望我这两篇博客能给童鞋们一点帮助。
下一篇文章将把struts2框架引入到我写的框架。
相关推荐
在本学习笔记中,我们将深入探讨JavaEE中的Spring框架,这是一个强大的、全面的企业级应用程序开发框架,它简化了Java开发并提供了丰富的功能。Spring的核心特性包括依赖注入(DI)、面向切面编程(AOP)以及对Java ...
该压缩包文件“javaEE-Spring-sturst2-MySql基于java新闻发布及管理系统(源码+数据库sql+lun文).rar”包含了一个完整的Java EE应用,它基于Spring、Struts2和MySQL数据库来构建一个新闻发布及管理系统。这个系统提供...
### JavaEE 学习笔记概览 #### 一、JavaEE 概念及发展历程 JavaEE(Java Platform, Enterprise Edition)是Sun Microsystems公司为简化企业级应用开发而提出的一套标准化平台,它提供了构建分布式系统的基本框架和...
传智168期JavaEE Spring姜涛的day38到day40的课程笔记,涵盖了Spring框架的基本概念、核心原理、版本演进、优势以及如何在项目中进行使用。这一系列知识构成了Spring框架的精华所在,是JavaEE开发者不可或缺的知识...
"JavaEE学习笔记.pdf" JavaEE(Java Enterprise Edition)是Java平台的企业版,用于开发大型企业级应用程序。作为JavaEE学习笔记,以下是相关的知识点总结: JavaEE架构 JavaEE架构主要由以下几个部分组成: * ...
根据提供的文档信息,以下是对JavaEE框架SSM(Spring+SpringMVC+MyBatis)课堂笔记中的关键知识点进行的详细解析。 ### 第一部分:Spring框架基础 #### 1. Spring简介 - **Spring概念**:Spring是一个开源的轻量级...
* 在 Spring 框架中,AOP 是一个核心组件,提供了对横切关注点的支持,例如安全检查、日志记录、事务管理等。 四、Spring MVC * Spring MVC 是一个基于 Java 的 Web 应用程序框架,提供了一个松散耦合的架构,帮助...
- **发展方向**: 包括JAVASE(Java Standard Edition,标准版)、JAVAME(Java Micro Edition,小型版)和JAVAEE(Java Enterprise Edition,企业版)。 - **Java语言特点**: - **简单性**: Java简化了许多C++中的...
事务管理是 Spring 框架提供的一种机制,用于管理数据库事务。Spring 提供了两种事务管理方式:编程式事务管理和声明式事务管理。 Spring5 新特性 ------------- Spring5 框架提供了一些新特性,如函数式编程、...
SSH框架集成(Struts + Spring + Hibernate)则进一步简化了JavaEE Web应用程序的开发过程,通过这三个框架的相互配合,可以快速搭建出结构清晰、可复用性强、易于维护的Web应用程序。无论是Struts还是Spring框架,都...
- JavaEE进阶之Spring事务深入浅出:虽然Spring是Java EE的一个补充框架,但它的事务管理部分在企业级应用中非常重要,值得深入学习。 - J2EEWeb应用开发技术教材:Web层的开发是Java EE应用中的关键部分,学习如何...
Spring提供一站式解决方案,涵盖了JavaEE开发的各个层面,包括Web层(如Spring MVC)、Service层(Bean管理,声明式事务)、DAO层(JDBC模板,ORM模板)。Spring的两大核心组件是IOC(Inversion of Control,控制...
4. **JTA (Java Transaction API)** 和 **JPA (Java Persistence API)**:JTA用于管理跨多个数据库操作的事务,确保数据一致性。JPA则为对象关系映射(ORM)提供标准接口,使得开发者可以使用面向对象的方式来操作...
### JavaEE 学习笔记概览 #### 一、JavaEE 概念及核心知识点 **JavaEE**(Java Platform, Enterprise Edition),即Java平台企业版,是为开发可移植、健壮、可伸缩、模块化且安全的服务器端应用而设计的。JavaEE ...
这份“学习JAVAEE三年来所有知识点的笔记”无疑是一份宝贵的资源,其中包含了JavaEE核心框架SSH(Struts2、Spring、Hibernate)和SSM(SpringMVC、Spring、MyBatis)的深入学习记录,以及MySQL数据库的存储过程使用...
"达内javaSE,javaEE个人学习所有基础笔记"是一个针对初学者的全面学习资源,涵盖了从Java Standard Edition (Java SE)的基础知识到Java Enterprise Edition (Java EE)的高级概念。 Java SE是Java的核心部分,它...
### SSH(Struts1.0+Spring+Hibernate)框架集成笔记 #### 一、概述 SSH框架集成,即Struts1.0 + Spring + Hibernate框架的整合应用,是Java Web开发中较为复杂的集成模式之一。它集合了MVC设计模式(通过Struts...