1.基本概念的理解
绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如:
C:\xyz\test.txt 代表了test.txt文件的绝对路径。http://www.sun.com/index.htm也代表了一个
URL绝对路径。
相对路径:相对与某个基准目录的路径。包含Web的相对路径(HTML中的相对目录),例如:在
Servlet中,"/"代表Web应用的跟目录。和物理路径的相对表示。例如:"./" 代表当前目录,
"../"代表上级目录。这种类似的表示,也是属于相对路径。
另外关于URI,URL,URN等内容,请参考RFC相关文档标准。
RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax,
(http://www.ietf.org/rfc/rfc2396.txt)
2.关于JSP/Servlet中的相对路径和绝对路径。
2.1服务器端的地址
服务器端的相对地址指的是相对于你的web应用的地址,这个地址是在服务器端解析的
(不同于html和javascript中的相对地址,他们是由客户端浏览器解析的)也就是说这时候
在jsp和servlet中的相对地址应该是相对于你的web应用,即相对于http://192.168.0.1/webapp/的。
其用到的地方有:
forward:servlet中的request.getRequestDispatcher(address);这个address是
在服务器端解析的,所以,你要forward到a.jsp应该这么写:
request.getRequestDispatcher(“/user/a.jsp”)这个/相对于当前的web应用webapp,
其绝对地址就是:http://192.168.0.1/webapp/user/a.jsp。
sendRedirect:在jsp中<%response.sendRedirect("/rtccp/user/a.jsp");%>
2.22、客户端的地址
所有的html页面中的相对地址都是相对于服务器根目录(http://192.168.0.1/)的,
而不是(跟目录下的该Web应用的目录)http://192.168.0.1/webapp/的。
Html中的form表单的action属性的地址应该是相对于服务器根目录(http://192.168.0.1/)的,
所以,如果提交到a.jsp为:action="/webapp/user/a.jsp"或action="<%=request.getContextPath()%>"/user/a.jsp;
提交到servlet为actiom="/webapp/handleservlet"
Javascript也是在客户端解析的,所以其相对路径和form表单一样。
因此,一般情况下,在JSP/HTML页面等引用的CSS,Javascript.Action等属性前面最好都加上
<%=request.getContextPath()%>,以确保所引用的文件都属于Web应用中的目录。
另外,应该尽量避免使用类似".","./","../../"等类似的相对该文件位置的相对路径,这样
当文件移动时,很容易出问题。
3. JSP/Servlet中获得当前应用的相对路径和绝对路径
3.1 JSP中获得当前应用的相对路径和绝对路径
根目录所对应的绝对路径:request.getRequestURI()
文件的绝对路径 :application.getRealPath(request.getRequestURI());
当前web应用的绝对路径 :application.getRealPath("/");
取得请求文件的上层目录:new File(application.getRealPath(request.getRequestURI())).getParent()
3.2 Servlet中获得当前应用的相对路径和绝对路径
根目录所对应的绝对路径:request.getServletPath();
文件的绝对路径 :request.getSession().getServletContext().getRealPath
(request.getRequestURI())
当前web应用的绝对路径 :servletConfig.getServletContext().getRealPath("/");
(ServletContext对象获得几种方式:
javax.servlet.http.HttpSession.getServletContext()
javax.servlet.jsp.PageContext.getServletContext()
javax.servlet.ServletConfig.getServletContext()
)
4.java 的Class中获得相对路径,绝对路径的方法
4.1单独的Java类中获得绝对路径
根据java.io.File的Doc文挡,可知:
默认情况下new File("/")代表的目录为:System.getProperty("user.dir")。
一下程序获得执行类的当前路径
package org.cheng.file;
import java.io.File;
public class FileTest {
public static void main(String[] args) throws Exception {
System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));
System.out.println(FileTest.class.getClassLoader().getResource(""));
System.out.println(ClassLoader.getSystemResource(""));
System.out.println(FileTest.class.getResource(""));
System.out.println(FileTest.class.getResource("/")); //Class文件所在路径
System.out.println(new File("/").getAbsolutePath());
System.out.println(System.getProperty("user.dir"));
}
}
4.2服务器中的Java类获得当前路径(来自网络)
(1).Weblogic
WebApplication的系统文件根目录是你的weblogic安装所在根目录。
例如:如果你的weblogic安装在c:\bea\weblogic700.....
那么,你的文件根路径就是c:\.
所以,有两种方式能够让你访问你的服务器端的文件:
a.使用绝对路径:
比如将你的参数文件放在c:\yourconfig\yourconf.properties,
直接使用 new FileInputStream("yourconfig/yourconf.properties");
b.使用相对路径:
相对路径的根目录就是你的webapplication的根路径,即WEB-INF的上一级目录,将你的参数文件放
在yourwebapp\yourconfig\yourconf.properties,
这样使用:
new FileInputStream("./yourconfig/yourconf.properties");
这两种方式均可,自己选择。
(2).Tomcat
在类中输出System.getProperty("user.dir");显示的是%Tomcat_Home%/bin
(3).Resin
不是你的JSP放的相对路径,是JSP引擎执行这个JSP编译成SERVLET
的路径为根.比如用新建文件法测试File f = new File("a.htm");
这个a.htm在resin的安装目录下
(4).如何读相对路径哪?
在Java文件中getResource或getResourceAsStream均可
例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",这里的/代表web
发布根路径下WEB-INF/classes
默认使用该方法的路径是:WEB-INF/classes。已经在Tomcat中测试。
解惑 spring 嵌套事务
/**
* @author 王政
* @date 2006-11-24
* @note 转载请注明出处
*/
在所有使用 spring 的应用中, 声明式事务管理可能是使用率最高的功能了, 但是, 从我观察到的情况看,
绝大多数人并不能深刻理解事务声明中不同事务传播属性配置的的含义, 让我们来看一下 TransactionDefinition 接口中的定义
- /**
- * Support a current transaction, create a new one if none exists.
- * Analogous to EJB transaction attribute of the same name.
- * <p>This is typically the default setting of a transaction definition.
- */
- int PROPAGATION_REQUIRED = 0;
- /**
- * Support a current transaction, execute non-transactionally if none exists.
- * Analogous to EJB transaction attribute of the same name.
- * <p>Note: For transaction managers with transaction synchronization,
- * PROPAGATION_SUPPORTS is slightly different from no transaction at all,
- * as it defines a transaction scopp that synchronization will apply for.
- * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
- * will be shared for the entire specified scope. Note that this depends on
- * the actual synchronization configuration of the transaction manager.
- * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
- */
- int PROPAGATION_SUPPORTS = 1;
- /**
- * Support a current transaction, throw an exception if none exists.
- * Analogous to EJB transaction attribute of the same name.
- */
- int PROPAGATION_MANDATORY = 2;
- /**
- * Create a new transaction, suspend the current transaction if one exists.
- * Analogous to EJB transaction attribute of the same name.
- * <p>Note: Actual transaction suspension will not work on out-of-the-box
- * on all transaction managers. This in particular applies to JtaTransactionManager,
- * which requires the <code>javax.transaction.TransactionManager</code> to be
- * made available it to it (which is server-specific in standard J2EE).
- * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
- */
- int PROPAGATION_REQUIRES_NEW = 3;
- /**
- * Execute non-transactionally, suspend the current transaction if one exists.
- * Analogous to EJB transaction attribute of the same name.
- * <p>Note: Actual transaction suspension will not work on out-of-the-box
- * on all transaction managers. This in particular applies to JtaTransactionManager,
- * which requires the <code>javax.transaction.TransactionManager</code> to be
- * made available it to it (which is server-specific in standard J2EE).
- * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
- */
- int PROPAGATION_NOT_SUPPORTED = 4;
- /**
- * Execute non-transactionally, throw an exception if a transaction exists.
- * Analogous to EJB transaction attribute of the same name.
- */
- int PROPAGATION_NEVER = 5;
- /**
- * Execute within a nested transaction if a current transaction exists,
- * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.
- * <p>Note: Actual creation of a nested transaction will only work on specific
- * transaction managers. Out of the box, this only applies to the JDBC
- * DataSourceTransactionManager when working on a JDBC 3.0 driver.
- * Some JTA providers might support nested transactions as well.
- * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
- */
- int PROPAGATION_NESTED = 6;
/** * Support a current transaction, create a new one if none exists. * Analogous to EJB transaction attribute of the same name. * <p>This is typically the default setting of a transaction definition. */ int PROPAGATION_REQUIRED = 0; /** * Support a current transaction, execute non-transactionally if none exists. * Analogous to EJB transaction attribute of the same name. * <p>Note: For transaction managers with transaction synchronization, * PROPAGATION_SUPPORTS is slightly different from no transaction at all, * as it defines a transaction scopp that synchronization will apply for. * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) * will be shared for the entire specified scope. Note that this depends on * the actual synchronization configuration of the transaction manager. * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization */ int PROPAGATION_SUPPORTS = 1; /** * Support a current transaction, throw an exception if none exists. * Analogous to EJB transaction attribute of the same name. */ int PROPAGATION_MANDATORY = 2; /** * Create a new transaction, suspend the current transaction if one exists. * Analogous to EJB transaction attribute of the same name. * <p>Note: Actual transaction suspension will not work on out-of-the-box * on all transaction managers. This in particular applies to JtaTransactionManager, * which requires the <code>javax.transaction.TransactionManager</code> to be * made available it to it (which is server-specific in standard J2EE). * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_REQUIRES_NEW = 3; /** * Execute non-transactionally, suspend the current transaction if one exists. * Analogous to EJB transaction attribute of the same name. * <p>Note: Actual transaction suspension will not work on out-of-the-box * on all transaction managers. This in particular applies to JtaTransactionManager, * which requires the <code>javax.transaction.TransactionManager</code> to be * made available it to it (which is server-specific in standard J2EE). * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_NOT_SUPPORTED = 4; /** * Execute non-transactionally, throw an exception if a transaction exists. * Analogous to EJB transaction attribute of the same name. */ int PROPAGATION_NEVER = 5; /** * Execute within a nested transaction if a current transaction exists, * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB. * <p>Note: Actual creation of a nested transaction will only work on specific * transaction managers. Out of the box, this only applies to the JDBC * DataSourceTransactionManager when working on a JDBC 3.0 driver. * Some JTA providers might support nested transactions as well. * @see org.springframework.jdbc.datasource.DataSourceTransactionManager */ int PROPAGATION_NESTED = 6;
我们可以看到, 在 spring 中一共定义了六种事务传播属性, 如果你觉得看起来不够直观, 那么我来转贴一个满大街都有的翻译
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)
在我所见过的误解中, 最常见的是下面这种:
假如有两个业务接口 ServiceA 和 ServiceB, 其中 ServiceA 中有一个方法实现如下
/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
// 调用 ServiceB 的方法
ServiceB.methodB();
}
那么如果 ServiceB 的 methodB 如果配置了事务, 就必须配置为 PROPAGATION_NESTED
这种想法可能害了不少人, 认为 Service 之间应该避免互相调用, 其实根本不用担心这点,PROPAGATION_REQUIRED 已经说得很明白,
如果当前线程中已经存在事务, 方法调用会加入此事务, 果当前没有事务,就新建一个事务, 所以 ServiceB#methodB() 的事务只要遵循最普通的规则配置为 PROPAGATION_REQUIRED 即可, 如果 ServiceB#methodB (我们称之为内部事务, 为下文打下基础) 抛了异常, 那么 ServiceA#methodA(我们称之为外部事务) 如果没有特殊配置此异常时事务提交 (即 +MyCheckedException的用法), 那么整个事务是一定要 rollback 的, 什么 Service 只能调 Dao 之类的言论纯属无稽之谈, spring 只负责配置了事务属性方法的拦截, 它怎么知道你这个方法是在 Service 还是 Dao 里 ?
说了这么半天, 那到底什么是真正的事务嵌套呢, 解释之前我们来看一下 Juergen Hoeller 的原话
PROPAGATION_REQUIRES_NEW starts a new, independent "inner" transaction for the given scope. This transaction will be committed or rolled back completely independent from the outer transaction, having its own isolation scope, its own set of locks, etc. The outer transaction will get suspended at the beginning of the inner one, and resumed once the inner one has completed.
Such independent inner transactions are for example used for id generation through manual sequences, where the access to the sequence table should happen in its own transactions, to keep the lock there as short as possible. The goal there is to avoid tying the sequence locks to the (potentially much longer running) outer transaction, with the sequence lock not getting released before completion of the outer transaction.
PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. íf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.
Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction.
For example, consider parsing a very large input file consisting of account transfer blocks: The entire file should essentially be parsed within one transaction, with one single commit at the end. But if a block fails, its transfers need to be rolled back, writing a failure marker somewhere. You could either start over the entire transaction every time a block fails, remembering which blocks to skip - or you mark each block as a nested transaction, only rolling back that specific set of operations, keeping the previous work of the outer transaction. The latter is of course much more efficient, in particular when a block at the end of the file fails.
Rolling back the entire transaction is the choice of the demarcation code/config that started the outer transaction.
So if an inner transaction throws an exception and is supposed to be rolled back (according to the rollback rules), the transaction will get rolled back to the savepoint taken at the start of the inner transaction. The immediate calling code can then decide to catch the exception and proceed down some other path within the outer transaction.
If the code that called the inner transaction lets the exception propagate up the call chain, the exception will eventually reach the demarcation code of the outer transaction. At that point, the rollback rules of the outer transaction decide whether to trigger a rollback. That would be a rollback of the entire outer transaction then.
So essentially, it depends on your exception handling. If you catch the exception thrown by the inner transaction, you can proceed down some other path within the outer transaction. If you let the exception propagate up the call chain, it's eventually gonna cause a rollback of the entire outer transaction.
也就是说, 最容易弄混淆的其实是 PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED, 那么这两种方式又有何区别呢? 我简单的翻译一下 Juergen Hoeller 的话 :
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
那么外部事务如何利用嵌套事务的 savepoint 特性呢, 我们用代码来说话
- ServiceA {
- /**
- * 事务属性配置为 PROPAGATION_REQUIRED
- */
- void methodA() {
- ServiceB.methodB();
- }
- }
- ServiceB {
- /**
- * 事务属性配置为 PROPAGATION_REQUIRES_NEW
- */
- void methodB() {
- }
- }
ServiceA { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodA() { ServiceB.methodB(); } } ServiceB { /** * 事务属性配置为 PROPAGATION_REQUIRES_NEW */ void methodB() { } }
这种情况下, 因为 ServiceB#methodB 的事务属性为 PROPAGATION_REQUIRES_NEW, 所以两者不会发生任何关系, ServiceA#methodA 和 ServiceB#methodB 不会因为对方的执行情况而影响事务的结果, 因为它们根本就是两个事务, 在 ServiceB#methodB 执行时 ServiceA#methodA 的事务已经挂起了 (关于事务挂起的内容已经超出了本文的讨论范围, 有时间我会再写一些挂起的文章) .
那么 PROPAGATION_NESTED 又是怎么回事呢? 继续看代码
- ServiceA {
- /**
- * 事务属性配置为 PROPAGATION_REQUIRED
- */
- void methodA() {
- ServiceB.methodB();
- }
- }
- ServiceB {
- /**
- * 事务属性配置为 PROPAGATION_NESTED
- */
- void methodB() {
- }
- }
ServiceA { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodA() { ServiceB.methodB(); } } ServiceB { /** * 事务属性配置为 PROPAGATION_NESTED */ void methodB() { } }
现在的情况就变得比较复杂了, ServiceB#methodB 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢? 从 Juergen Hoeller 的原话中我们可以找到答案, ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint(注意, 这是本文中第一次提到它, 潜套事务中最核心的概念), 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:
1. 改写 ServiceA 如下
- ServiceA {
- /**
- * 事务属性配置为 PROPAGATION_REQUIRED
- */
- void methodA() {
- try {
- ServiceB.methodB();
- } catch (SomeException) {
- // 执行其他业务, 如 ServiceC.methodC();
- }
- }
- }
ServiceA { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodA() { try { ServiceB.methodB(); } catch (SomeException) { // 执行其他业务, 如 ServiceC.methodC(); } } }
这种方式也是潜套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点. (题外话 : 看到这种代码, 似乎似曾相识, 想起了 prototype.js 中的 Try 函数 )
2. 代码不做任何修改, 那么如果内部事务(即 ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此),
外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback (+MyCheckedException).
上面大致讲述了潜套事务的使用场景, 下面我们来看如何在 spring 中使用 PROPAGATION_NESTED, 首先来看 AbstractPlatformTransactionManager
- /**
- * Create a TransactionStatus for an existing transaction.
- */
- private TransactionStatus handleExistingTransaction(
- TransactionDefinition definition, Object transaction, boolean debugEnabled)
- throws TransactionException {
- ... 省略
- if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
- if (!isNestedTransactionAllowed()) {
- throw new NestedTransactionNotSupportedException(
- "Transaction manager does not allow nested transactions by default - " +
- "specify 'nestedTransactionAllowed' property with value 'true'");
- }
- if (debugEnabled) {
- logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
- }
- if (useSavepointForNestedTransaction()) {
- // Create savepoint within existing Spring-managed transaction,
- // through the SavepointManager API implemented by TransactionStatus.
- // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
- DefaultTransactionStatus status =
- newTransactionStatus(definition, transaction, false, false, debugEnabled, null);
- status.createAndHoldSavepoint();
- return status;
- }
- else {
- // Nested transaction through nested begin and commit/rollback calls.
- // Usually only for JTA: Spring synchronization might get activated here
- // in case of a pre-existing JTA transaction.
- doBegin(transaction, definition);
- boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
- return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
- }
- }
- }
/** * Create a TransactionStatus for an existing transaction. */ private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { ... 省略 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { if (!isNestedTransactionAllowed()) { throw new NestedTransactionNotSupportedException( "Transaction manager does not allow nested transactions by default - " + "specify 'nestedTransactionAllowed' property with value 'true'"); } if (debugEnabled) { logger.debug("Creating nested transaction with name [" + definition.getName() + "]"); } if (useSavepointForNestedTransaction()) { // Create savepoint within existing Spring-managed transaction, // through the SavepointManager API implemented by TransactionStatus. // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization. DefaultTransactionStatus status = newTransactionStatus(definition, transaction, false, false, debugEnabled, null); status.createAndHoldSavepoint(); return status; } else { // Nested transaction through nested begin and commit/rollback calls. // Usually only for JTA: Spring synchronization might get activated here // in case of a pre-existing JTA transaction. doBegin(transaction, definition); boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER); return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null); } } }
一目了然
1. 我们要设置 transactionManager 的 nestedTransactionAllowed 属性为 true, 注意, 此属性默认为 false!!!
再看 AbstractTransactionStatus#createAndHoldSavepoint() 方法
- /**
- * Create a savepoint and hold it for the transaction.
- * @throws org.springframework.transaction.NestedTransactionNotSupportedException
- * if the underlying transaction does not support savepoints
- */
- public void createAndHoldSavepoint() throws TransactionException {
- setSavepoint(getSavepointManager().createSavepoint());
- }
/** * Create a savepoint and hold it for the transaction. * @throws org.springframework.transaction.NestedTransactionNotSupportedException * if the underlying transaction does not support savepoints */ public void createAndHoldSavepoint() throws TransactionException { setSavepoint(getSavepointManager().createSavepoint()); }
可以看到 Savepoint 是 SavepointManager.createSavepoint 实现的, 再看 SavepointManager 的层次结构, 发现
其 Template 实现是 JdbcTransactionObjectSupport, 常用的 DatasourceTransactionManager, HibernateTransactionManager
中的 TransactonObject 都是它的子类 :
JdbcTransactionObjectSupport 告诉我们必须要满足两个条件才能 createSavepoint :
2. java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+
3. Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0
确保以上条件都满足后, 你就可以尝试使用 PROPAGATION_NESTED 了. (全文完)
相关推荐
### Java中相对路径与绝对路径问题详解 #### 一、基本概念理解 在Java中,理解和正确使用相对路径和绝对路径对于开发Web应用程序至关重要。这些路径不仅涉及到文件系统的操作,还涉及到了网络资源的访问。 **绝对...
以下是对Java Web中相对路径与绝对路径问题的深入总结: ### 一、路径概念与标准 #### 1. URL与URI URL(Uniform Resource Locator)统一资源定位符,是一种用于标识网络上资源位置的标准格式,如`...
"Java 中相对路径与绝对路径的问题" Java 中的路径问题一直是困扰许多编程人员的问题之一。在 Java 中,我们需要了解相对路径和绝对路径的概念,以及如何获取它们。下面我们将详细地讨论 Java 中的相对路径和绝对...
### Java中File的相对路径与绝对路径总结 在Java Web开发过程中,经常需要处理文件的读写操作,尤其是在运行时获取配置文件、动态加载对象等情况。对于这些需求,理解和掌握文件的相对路径与绝对路径至关重要。 ##...
在Web开发中,尤其是在使用Java Servlet和JSP技术时,正确理解和使用相对路径和绝对路径至关重要。 ##### 2.1 服务器端的地址 服务器端的相对地址是指相对于你的Web应用的地址,这个地址是在服务器端进行解析的,...
1. **获取当前应用的相对路径与绝对路径** - **根目录所对应的绝对路径** - 方法:`request.getRequestURI()` - `request.getRequestURI()` 返回客户端请求的资源的相对路径(相对于当前上下文)。 - **文件的...
Java路径问题最终解决方案 —可定位所有资源的相对路径寻址 通过相对classpath路径实现自由寻找资源的助手类的源代码
JAVA 文件中获取项目的相对路径 在 JAVA 文件中获取项目的相对路径是非常重要的,特别是在 ...通过了解绝对路径和相对路径的概念,我们可以更好地获取当前应用的相对路径和绝对路径,从而更好地处理文件和目录的操作。
本篇文章将深入探讨绝对路径与相对路径的概念、它们之间的转换以及如何在C++、Java和Python中实现这种转换。 ### 绝对路径与相对路径 **绝对路径**: - 它是文件系统的完整路径,从根目录(如Windows下的"C:\"或...
根据给定的信息,本文将详细解释Java实现的最短路径问题动态规划算法。该程序的主要目的是寻找图中各个节点到指定终点的最短路径,并输出每个节点到终点的最短距离以及达到这些最短距离时的决策路径。 ### 1. 问题...
约定,文件或目录的路径名由斜线(/)或反斜线()分割,此外,相对路径中可以采用'.'表示当前路径,'..'表示当前路径的父路径,即上一级目录。 Java 编程时,需要注意,''后面表示的是转义字符,因此需要...
### Java 文件路径获取方法详解 #### 一、引言 在Java开发中,经常会遇到需要获取文件路径的情况,尤其是在处理配置文件、图片等资源时。本文将详细介绍Java中获取文件路径的各种方法及其应用场景,帮助开发者更好...
在Java编程中,处理中文路径问题是一个常见的挑战,尤其是在Windows操作系统环境下。中文字符在路径中可能会引起编码问题,导致程序无法正确读取或写入文件。这个问题主要涉及到字符编码、文件I/O操作以及系统环境的...
java区分绝对路径和相对路径.doc
路径主要分为两种类型:相对路径和绝对路径。 **1. 相对路径与绝对路径** - **相对路径**:它是相对于某个基准目录的路径。例如,如果你在Web应用的`/resources`目录下有一个配置文件,而基准目录是当前运行的JSP...
在Java中,文件路径可以是绝对路径或相对路径。绝对路径是从根目录开始的完整路径,它指明了文件的确切位置。相对路径则是相对于当前工作目录的路径,它的解析依赖于程序运行时的工作目录。在处理文件路径时,开发者...
最全最清楚的Java 以及JavaEE 相对路径和绝对路径解析,能让我们正确使用相对路径
JSP中java脚本获取绝对路径 。
在Java中,路径分为绝对路径和相对路径,这两种路径又有不同的表现形式。 一、URI形式的绝对资源路径 例如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b 这是一个URI(Uniform Resource Identifier)...