0.头文件
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.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
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
1.<context:property-placeholder location="classpath:system/*.properties" />
导入src目录下的system下的所有properties文件。
2.<context:annotation-config />
3.<tx:annotation-driven transaction-manager="transactionManager" />
注 : Controller可以使用@Transactional
在使用SpringMvc的时候,配置文件中我们经常看到 annotation-driven 这样的注解,其含义就是支持注解,一般根据前缀 tx、mvc 等也能很直白的理解出来分别的作用。<tx:annotation-driven/> 就是支持事务注解的(@Transactional) 、<mvc:annotation-driven> 就是支持mvc注解的,说白了就是使Controller中可以使用MVC的各种注解。
首先,<tx:annotation-driven/> 会有一个属性来指定使用哪个事务管理器,如:<tx:annotation-driven transaction-manager="transactionManager" />。然后事务管理器 transactionManager 会引用 dataSource (如果我们使用JPA或hibernate,也需要指定一个 entityManagerFactory ),dataSouce 肯定就是直接对数据库的了。
这样逐层引用下去,所以我们使用@Transactionl 注解可以控制事务就通俗易懂了。另外要提一下的就是 spring 是使用 aop 通过 asm 操作java字节码的方式来实现对方法的前后事务管理的。
说到这里,已经有了对 <tx:annotation-driven/> 的简单理解,那我们是否就可以在程序中所有被spring管理的类上都可以使用@Transactional注解了呢,在Service上可以使用@Transactional 注解这个是肯定的了,那总有些人也想弄明白能否在Controller 使用?答案显然是“不一定”的(与时间配置有关),下面做下解释:
在 spring-framework-reference.pdf 文档上有这样一段话:
<tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.
意思就是:<tx:annoation-driven/>只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解,如果你把它放在Dispatcher的应用上下文中,它只检查控制器(Controller)上的@Transactional注解,而不是你services上的@Transactional注解。
所以,可以确定的是我们是可以在Controller上使用事务注解的,但是我们不推荐这样做,这里只是为了说明spring对<tx:annotation-driven/>的使用。
4.<task:executor id="taskExecutor" pool-size="1-20"
queue-capacity="30" keep-alive="60" />
5.<task:scheduler id="scheduler" pool-size="1" />
6.<task:annotation-driven executor="taskExecutor"
scheduler="scheduler" />
Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种Spring 实用注解来调度定时任务。 配置自动调度的包和定时开关
1.在需要加载spring的配置文件里spring.xml / applicationContext.xml 添加
[html] view plain copy xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
<task:executor id="taskExecutor" pool-size="1-20"
queue-capacity="30" keep-alive="60" />
注 :整合TaskExecutor线程池的配置
核心线程数:pool-size ;
队列最大长度:queue-capacity; 线程池维护线程所允许的空闲时间,默认为60s:keep-alive在实现层Impl声明并注入:
@Resource(name = "taskExecutor") private TaskExecutor taskExecutor;在方法里调用:
try { taskExecutor.execute(new Runnable() { public void run() { //这里编写处理业务代码 } }); } catch (Exception e) { e.printStackTrace(); } 配置调度和注解调度
[html] view plain copy <!-- 配置调度 需要在类名前添加 @Service --> <!-- <task:scheduled-tasks> <task:scheduled ref="demoTask" method="myTestWork" cron="0/10 * * * * ?"/> </task:scheduled-tasks> --> <!-- 不通过配置调度,需要在类名前 @Component/@Service,在方法名 前添加@Scheduled(cron="0/5 * * * * ? ")-->
在web.xml配置里添加启动时要扫描的配置文件和监听
[html] view plain copy <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 添加调度的包
类测试
[java] view plain copy @Service public class demo { @Scheduled(cron="0/5 * * * * ? ") public void myTestWork(){ System.out.println("ssss"); } }
7.<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="url" value="${db.url}" />
<property name="driverClassName" value="${db.driver}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="maxTotal" value="50" />
<property name="maxIdle" value="50" />
<property name="minIdle" value="5" />
<property name="initialSize" value="5" />
<property name="maxWaitMillis" value="-1" />
</bean>
配置数据源dataSource
此外还需要src文件夹里新建一个jdbc.properties文件,里面的内容为如下:
db.driver=com.mysql.jdbc.Driver db.url=jdbc:mysql://172.20.13.55:3306/study?useUnicode=true&characterEncoding=utf8 db.username=study db.password=******
<!-- 连接池的最大值,同一时间可以从池分配的最多连接数量,0时无限制 --> <property name="maxTotal" value="${maxActive}" /> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 ,0时无限制--> <property name="maxIdle" value="${maxIdle}" /> <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="${minIdle}" /> <!-- 连接初始值,连接池启动时创建的连接数量的初始值 --> <property name="initialSize" value="${initialSize}" /> <!-- 获取数据库连接的最长等待时间,-1表示无限期等待 --> <property name="maxWaitMillis" value="-1" />
8.
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="jp.iesolutions.study.models" />
<property name="annotatedPackages">
<list>
<value>jp.iesolutions.study.models</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.DB2Dialect
hibernate.show_sql=true
hibernate.jdbc.batch_size=20
hibernate.autoReconnect=true
</value>
</property>
</bean>
<!-- 定义Hibernate的SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 依赖注入数据源,正是上文定义的dataSource -->
<property name="dataSource" ref="dataSource" />
<!-- 实现实体类的扫描例如<property name="" value="com.xxx.entity" />,会解析成"classpath*:com/xxx/entity**/*.class",
这个路径可以找出com/xxx/entity根目录下的类文件 -->
<property name="packagesToScan" value="jp.iesolutions.study.models" />
<!-- 定义Hibernate的SessionFactory属性 -->
<property name="hibernateProperties">
<!-- 指定Hibernate的连接方言 -->
hibernate.dialect=org.hibernate.dialect.DB2Dialect
<!-- 是否显示Sql语句 -->
hibernate.show_sql=true
<!--Batch Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。Batch Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。
-->
hibernate.jdbc.batch_size=20
<!-- Hibernate连接数据库超时设置-->
hibernate.autoReconnect=true
9. <beanid="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
定义了一个事务管理器transactionManager
10.
<beanid="transactionProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,-myException</prop>
<prop key="del*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
配置了事务代理
<!-- 为事务代理工厂Bean注入事务管理器 -->
<propertyname="transactionManager"ref="transactionManager"></property>
<!-- 指定事务属性 -->
PROPAGATION_MANDATORY:要求调用该方法的线程必须处于事务环境中,否则抛出异常
PROPAGATION_NESTED:如果执行该方法的线程已处于事务环境下,依然启动新的事务,方法在嵌套的事务里执行。如果执行方法的线程为处于事务中,也启动新的事务,然后执行该方法,此时与PROPAGATION_REQUIRED相同
PROPAGATION_NEVER:不允许调用该方法的线程处于事务环境下,如果调用该方法的线程处于事务环境下,则抛出异常
PROPAGATION_NOT_SUPPORTED:如果调用该方法的线程处在事务中,则暂停当前事务,然后执行该方法
PROPAGATION_REQUIRED:要求在事务环境中执行该方法,如果当前执行的线程已处于事务中,则直接调用;如果当前执行线程不处于事务中,则启动新的事务后执行该方法
PROPAGATION_REQUIRES_NEW:要求在事务环境中执行该方法,如果当前执行的线程已处于事务中,则暂停当前事务,启动新事务后执行该方法;如果当前执行线程不处于事务中,则启动新的事务后执行该方法
PROPAGATION_SUPPORTS:如果当前执行线程处于事务中,则使用当前事务;不过不在事务中,则不使用事务