TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
沙发
发表于 2014-09-03 21:20:54
|只看该作者
2、 定义自动代理事务管理器 9 x+ n2 B. H7 e9 n# z* _( A
1 N% S' ^; R) _8 g# H
<!-- 定义BeanNameAutoProxyCreator-->
4 x3 W$ ]( A5 |: j# H5 s% I& w; w' i o% X; V
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> : N& d" q( \5 j7 X, w
( h: `+ Z! n+ Q6 |<!-- 如果服务层对象是接口实现类,则需要设置proxyTargetClass属性为true --> 9 j3 g1 d7 |$ S2 L
' w2 [) ]7 a2 b1 |* h+ x<!--<property name="proxyTargetClass" value="true"-->
. \8 v6 A4 j/ O* [ T; Q9 V* T0 O# A7 ] Y9 U
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
( O5 j4 C) E p' G( K5 u- k# C# q0 \3 L. \9 b
<property name="beanNames">
2 V- @: o; P: [3 d, y* q! X
) g" B$ S" e& A+ k+ O <!-- 下面是所有需要自动创建事务代理的bean-->
6 N9 ]& F8 F R0 |# ]; k( n
* W' q0 Y' C# ~$ a" W7 c4 R/ } <list>
# v2 b5 b/ q4 F# A+ E: W, |3 q; K" V8 `" w+ A# H
<value>us</value>
* @/ L4 v4 N' z. n0 }) o( C g y% O, t) X
</list> # u8 V# Y' c( j( O5 ?& N0 L
) n( L( ]% ^( C: ^" y9 S, x
<!-- 此处可增加其他需要自动创建事务代理的bean-->
' g2 P1 f- }3 J- Q) ]# b6 g
/ j% A& e9 ~: M4 T </property> 9 P* Q4 R& `4 J* s% n1 F
, k9 B! }% ~* A6 M& ` j <!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
# |" b, L! Q9 @9 T0 @5 ?# s- P1 L
7 w6 o+ Y6 E A: q8 N6 O4 Q7 s <property name="interceptorNames">
' [' Q I2 `" U% u" l7 m' t5 j' ]2 F+ P) r3 L! k, B, O
<list>
( @/ Q8 w1 I4 Z* T7 q9 L) n# l/ m, O3 p2 B6 @
<!-- 此处可增加其他新的Interceptor -->
' q' \3 _/ h4 L* {& F% |
7 V% c7 K; @) N. |( U1 _- e, j <value>transactionInterceptor</value>
- v" q$ T" z" B/ l+ A+ X6 K, j4 l# y& H/ d
</list> & A, E* U6 H6 H. w$ G1 v7 Z! F
, P& [( F. ?/ X+ X4 K </property> 9 [1 ^7 Z# Z# q5 U3 `7 U
* L/ Y j3 U3 F2 M" w! x1 ~
</bean>
/ y: v1 |6 B7 w$ P# k( F1 O' w' ]0 e% B" _) c& L
然后我们在程序中调用时应如下:
, N1 U; S# ?5 D6 W, s9 l3 [7 n1 M4 g9 h" A7 t
UserService us = (UserService) app.getBean("us");
+ F7 P E: Z' `0 M7 W, s) S$ @, w& A( r) K* H7 G" L L
注:注意与上面使用TransactionProxyFactoryBean时的调用区别,此处我们用getbean时直接取原服务层对象的id,不需要去配置目标bea,这也正是 + m% D- i: ?# R, j. J! v& b. f& ]
, F/ O. C9 ?4 T2 I/ Y
BeanNameAutoProxyCreator(根据bean名称自动代理)的含义所在
5 Q1 r* ^$ R h* i {' {' Z
- N/ ^" y5 `% i$ I0 a3 I4 _
0 Y6 a. {1 A* F3 ?
- ?5 B2 x) x9 [6 I% n/ W) p# m附录: # e( Q9 D' F4 O l" ^" q0 w' h$ t
: \) O y6 _- B6 S
1、关于hibernate的属性详解:
. b7 @1 a- B0 v, a
0 V$ s( S+ V1 S) _3 p+ L<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 8 H+ z8 \9 z5 p, o
' b2 q8 G" M$ G4 ~
<!-- 以下配置都是使用 jdbc.properties 属性文件中的配置,而之所以可以这样写,就是因为有 属性占位符配置的原因 -->
3 s6 y( J' s# F3 V9 }
% }# v; o" U9 ], `<property name="driverClass" value="${jdbc.driverClassName}"/> ~8 q+ D9 ?! X. X
8 G1 p! K. z5 S) f/ B6 f2 H<property name="jdbcUrl" value="${jdbc.url}"/>
, Y: i+ [# m; p9 B" B% f ]
, k+ t. f+ B& J<property name="user" value="${jdbc.username}"/> 9 K/ X2 S( n+ |9 a
/ O6 M7 v1 f% h. s, U( \. ?<property name="password" value="${jdbc.password}"/>
8 j* s; j' ~, ]1 D6 b- m# D1 Q1 a" X @' z* U& n) F1 g( X0 W
<!-- 连接池维持的最小的连接个数 --> : Z' _' |) {0 G/ @9 b1 \9 F" S
# H( O5 u! i3 G6 m) {
<property name="minPoolSize" value="5"/>
8 m7 q. Z' r4 k; k; Y- I( P& S9 j" R+ }9 Y- L- ~/ T+ X6 Y
<!-- 连接池维持的最大的连接个数 -->
& P' M+ S+ l3 ~& ?* l% y; Q8 x' D6 i' E% ~& j! Z, D
<property name="maxPoolSize" value="20"/>
+ H" y% {. ?8 {- [9 X. L, _+ T; [( L' W) V; G5 E7 c( \1 F3 E
<!-- 最大空闲时间, 当某个连接在这个时间内没活动后将从池中移除,前提是池中至少多于最少的连接数: minPoolSize --> 2 m0 W9 w2 `, L7 y
6 C! v: r2 V. R2 M) Q- }4 Y
<property name="maxIdleTime" value="1800"/> ) P( D" W3 b2 d2 e! c4 F* `
; R; Y, Q" X3 a7 z<!-- 为加强准备语句的执行性能,此参数指定被缓存的 PreparedStatement 的个数 -->
* V, U; C! y$ r0 W
; K: P/ Z, u1 v- b- s<property name="maxStatements" value="50"/>
. [% y, e' s, u) } l3 v+ ]
$ Q% k( f9 f' P1 b+ [0 P</bean> 8 u$ G; O$ u* L. z
& Q6 b% W3 u' A5 y, q* x
4 R5 E$ l' H0 Z# e: Z7 j6 g8 y$ A* M5 {6 E/ Y% ~: {
Hibernate 会话厂 SessionFactory
# b. a+ ?. j, m, K: y( u7 F& p; D1 e! u5 I' J1 Q9 M
Session 就是用于每次与数据库会话的,因此需要: ! v7 }/ B! a1 S b' T" L
9 C0 \6 c* F6 O( q; N数据库的配置参数,这些参数就是 上面的数据源指定的! 因此我们只需引用即可: ref="dataSource";
% {, j- r" N7 n( L0 c" i; L, r
* ~0 X+ f& z- Q3 r8 l6 X实体映射配置 hibernate.cfg.xml 配置
C: n2 J3 W0 U7 ~- ]0 E5 ~/ D$ X3 u' i5 Q/ N" p4 B/ U) t
结果缓存配置(这里使用的是开源的 ehcache) 6 H, v) V) h% j5 A3 n- h
$ C; j, ^2 O A
* n6 ^( c" D( w8 e' k( e' M7 c
* j. Z7 o$ o, f2 H$ [+ D<!-- Hibernate SessionFactory -->
- @& L& s/ K/ K; K5 U; E/ J7 j7 P
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> ' M- v0 t6 v* n
8 @, t. D$ z- F. B. g# r<!-- 引用前面定义的数据源 -->
, m( o/ M# _3 }; `: `3 {& A# u# O( i1 n3 z0 e
<property name="dataSource" ref="dataSource"/>
. ^: z" ^# X* }$ ^ C$ y8 r
; B5 f! A& A, ]( S2 f& ~) s) g<!-- 所有实体映射文件列表, 所有的 hbm.xml 文件 -->
: f$ [# Q% @ m D/ T O3 Z' K( f( a5 a0 \) c; Q% e j
<property name="mappingResources"> ; x1 n8 v) x2 S
3 x, r9 u$ c6 p* H( E! f' }
<list> . l; e& L/ l/ C* u- K" N$ I
1 B5 i, I. w+ b' H$ ?" V: ^" A<value>org/springframework/samples/jpetstore/domain/Account.hbm.xml</value> 8 l$ L2 v( m8 \# Z; @ A8 m0 o
1 T* A2 ~; ^5 v<value>org/springframework/samples/jpetstore/domain/Banner.hbm.xml</value>
% V L) j, m. u; y* A8 \( [* |/ I4 c* c, ~5 S- y
<value>org/springframework/samples/jpetstore/domain/Category.hbm.xml</value>
) ? b4 D6 I2 `3 Z% h0 E. o/ l
) I6 C0 S- _# q6 N' `' b<value>org/springframework/samples/jpetstore/domain/Inventory.hbm.xml</value>
3 ?( E2 `) S# N( z# u" U6 I! Z( W' ]
<value>org/springframework/samples/jpetstore/domain/Item.hbm.xml</value> 6 w J+ n6 g) {- C+ a
$ K3 Y/ @" d) ^1 a) T<value>org/springframework/samples/jpetstore/domain/LineItem.hbm.xml</value> 5 ]: t4 U7 L' W* J2 Q6 ^
2 ~- R6 Q9 w5 s0 E. |
<value>org/springframework/samples/jpetstore/domain/Order.hbm.xml</value> & j- [+ Z6 F7 E3 W' [/ F/ S
0 I& _2 |' I4 S( t4 d6 E7 S1 R
<value>org/springframework/samples/jpetstore/domain/Product.hbm.xml</value> 5 z. V1 k7 C8 G9 j7 x& H
3 h& }5 {' A; F$ e/ s. i, l m
<value>org/springframework/samples/jpetstore/domain/Supplier.hbm.xml</value> ( K2 ~ l' @4 x1 N' F3 p, _
J& h/ P9 ^5 M% J
</list>
( {6 n f) z6 }( _5 F
w; o: Y9 A" P$ M</property>
. }+ ~" q" n$ W) e/ @) q
9 L6 l; ?, [5 ?! v<!-- 传统上的 hibernate.cfg.xml 文件的参数放在这里 -->
5 D$ @( c- K9 i2 q( q0 m- D
# H9 r) ?1 h' F# I8 S<property name="hibernateProperties"> - L7 O; T. M3 J8 k) u" n; W
5 Y: b6 E, g5 `1 R' G
<props> ; l& Y# @$ u/ G; _7 r/ l# j) o
, T. y. |1 m) f" W2 U/ s# y# H4 e' g
<!-- 指定数据库方言 -->
) L/ R9 w0 ~! a% z+ g. {
, S0 l9 k+ l8 V<prop key="hibernate.dialect">${hibernate.dialect} 6 i3 u, X0 r, A( G& p
4 a! ~, n3 F N" L! g4 V6 b
</prop>
# [4 f7 {' [% j3 k& _$ ]& r7 K9 W* T+ U: T; d" H
<!-- 是否在日志中输出所有Hibernate与数据库交互的SQL语句 --> ( H i& ?! w# l. v4 y) t+ f
; J+ `/ m/ H2 ~7 n
<prop key="hibernate.show_sql">true</prop>
5 O% x7 E a/ G, J1 L
* b8 N3 M7 N+ F% s7 _0 j<!-- 是否在日志中输出的SQL 语句格式化成易读形式 --> & ?. V+ A5 d6 Z7 R' S6 j( N: i
, b9 R( o2 e7 a<prop key="hibernate.format_sql">true</prop>
4 F! |, e# _% G7 E; n5 J- V. a
( p7 C1 V# d/ j* {<!-- 是否显示统计形式,一般在测试阶段使用 --> & Q7 ? b0 p% K) X; P+ @- b
* A; P; _/ x% y8 d+ }<prop key="hibernate.generate_statistics">true</prop>
& }5 }' x+ ?: a% h0 t
- k, T9 X- |4 ?<!-- 对于级联查询,一次性获取的级联深度, @todo 需进一步研究 --> ' E! L- `: O* N! r9 j" Y9 Y
+ T2 d z' g. N. J- t% W
<prop key="hibernate.max_fetch_depth">2</prop>
- ~& E' M/ m$ O
4 O0 L* O( f) s. A1 [<!-- 7 n+ C! S6 [$ c( C
: H, k, w, `1 ^; T; _' U
Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数,一般设置为30、50、100。
# t$ r e' ?$ m/ F% }2 a$ B: C2 a; I* X, |3 B6 P. S6 p; h9 s
Oracle数据库的JDBC驱动默认的Fetch Size=15,设置Fetch Size设置为:30、50,性能会有明显提升,如果继续增大, 7 L- l: I* K+ i! X, z7 f; t
2 ~* z9 W5 Q' O) ] h8 f' W
超出100,性能提升不明显,反而会消耗内存。 7 h- k$ C+ p6 o: Z" c' i6 I& l6 ^
U& y/ H9 S( o; X" a6 c-->
( r1 c" y/ p: q9 x# A8 y" }+ i/ R% k0 l+ @
<prop key="hibernate.jdbc.fatch_size">100</prop>
, p* K4 v' u" d* i9 N0 C
/ e3 p8 o5 ]( D<!-- 9 D4 w7 y+ C7 q! S, l% @
. W& d. S. @. X) k/ X不必等到累计到50个SQL之后才执行.只要事务commit后,不管缓存中有多少条sql语句都要执行.
6 z- z! t" [* C6 a+ \# N
. R+ ?5 A8 V& y% I" O1 Khibernate.jdbc.batch_size参数只是设定一次最多可以提交多少sql语句的上限,提高sql语句的执行效率
; J8 w6 L8 H5 ?6 e% G$ U+ V* o
$ D2 i X, Q: f8 V( b3 F! d9 l2 ~) W-->
' a$ p/ P8 c( T7 l- o, C' F3 u# D4 x; c5 J8 p. ?
<prop key="hibernate.jdbc.batch_size">50</prop>
) W' \/ }% D% k! X- ^2 U* w1 W( B* Q# \, R2 A) X9 @7 T" H
<!--
! {8 `, m2 j( {3 u; V" ]% b/ H% {* A' U1 e. w) M% Z; b3 l1 \
(1)create 在每次SesstionFactory 构建时(一般是应用重启时,或者伴随着应用服务器重启时),先将之前数据库中的所有数据全 ; ]/ ~5 I# J& y
+ V L: d& G( r1 q* \
部清空,后紧跟着根据所有的hbm.xml 映射文件重新创建新的数据库表 , Q1 v( A0 [7 D6 m; I
% i# X$ L' @* h8 ~0 v4 E% {8 i
4 L- r% g0 @2 ^( ^4 L' l# E8 y/ i7 Q: V- J6 e I& l
(2)create-drop 除了create 的所有含义之外,在每次应用的退出前,将进行一次数据空清空。因此这个配置将有两次清空操作,
! E/ P2 D, j3 d, f: h& u }
# u5 j1 L8 x: ~4 I! t一次是退出,一次是启动时。 * u1 i$ ]7 r4 q- i: u$ O
* ~, D; M$ R& n5 s5 B
! V9 i# f% i+ C) q" T/ z! m! Y1 Q* R& y* O5 I2 Q0 ~; }# K
(3)update
9 S* _$ I N4 @# x$ Y. [) F; j# t4 S$ b0 c) j/ J
如果在开发阶段理发了实体对象的映射文件(hbm.xml) 的定义后,此配置将后台的数据库表进行更新(如增加表的列)
, ]$ G) }1 V7 d( i- R! }: o
S* [" w ~! J8 z: U2 q# R# F) J/ ~/ f n$ i7 V
$ Z# H4 B8 Q U1 a# ]" `) A(4)validate
1 a8 a3 Q% K8 a( f: D# @" B$ j0 D; H" [+ U2 [
用于校验现有的表与现有的配置是否一致。
+ L) V1 G ]; i! R7 j% b1 z
$ M6 C2 }' R' M- Z7 j8 Z. h* q--> * `$ S& w7 D$ S. s
$ ?5 ?$ }. {" T0 R<prop key="hibernate.hbm2ddl.auto">update</prop>
# X" Q9 [) U! [% b3 {+ g
. O8 @( Z. d, j# H9 Z<!-- 见下面的解释 -->
& [; |7 w7 a) g# \) K( B+ {
1 t6 O" y9 q7 T2 q8 H<prop key="hibernate.hbm2ddl.auto">update</prop> 9 \- k0 J6 Z6 y
4 n+ v8 y9 O" [. {0 \1 O; z9 _<!--结果缓存配置:- 将ehcache.xml 置于 classpath 中- 如果不设置“查询缓存”, * Y8 L% A+ }; X a* Q, w9 @/ v( Y; W
3 H9 e' M% D9 @. }& @那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、 list()、 4 B6 ^0 a+ z2 m( j* L6 T
" Z' C& h& R, v1 m7 Y
Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置
9 ?' Z' w9 |6 }6 \! X0 l0 O
* \3 s7 y# M4 P# F, ihibernate.cache.use_query_cache true 才行- 在Hbm文件中添加<cache usage="read-only"/>-
2 K3 t2 Q \& k* E$ @. x2 o$ s) B0 V3 a& F. @# N+ S1 y
如果需要“查询缓存”,还需要在使用Query或Criteria()时设置其setCacheable(true);属性-->
7 @9 b4 R5 c$ ]: j% L
" }" f7 J' l. F( l2 m5 i<prop key="hibernate.cache.use_query_cache">true</prop> - Q) Z' D* A; H7 ] L
9 ?: j9 a7 ?, ~: u. \<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 1 F% W/ D) |6 X6 { `5 G& z
# f) a6 U$ X% l! {</props>
+ t" o |) y3 Y6 A
( `7 z1 C0 h/ C! \5 c; @: I- k</property>
5 a2 J% }/ I, v' {* x/ M( ~) \, { x4 ^5 W
<!-- 为解决 merge()方法语义的歧义 @todo 以后进一步解析或者你可以看一下相应的文档 --> 1 C$ Z0 }7 g; c7 ]4 k* P0 U
, R9 v" O, l# H, X, m<property name="eventListeners"> ' D, x' A; H$ k7 i1 p! W0 [
4 I# E/ @8 a3 E6 R! B: {2 z! x8 ~<map><entry key="merge"> 8 o7 X' a8 D5 o V
f K1 a f+ a0 N<bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/> ) T0 N# k8 p4 ?% z/ y
- O$ P9 m$ n" _0 u
</entry></map> ' j; k' x1 p& M" B
, Y3 k1 n- I, X( k
</property> , S1 p- ]" [- o% u# Z- z
5 o7 I# M: Z K' v* U+ l) w7 D</bean> ) K. ]2 N. t7 }, Z5 s
% O" {! x v- O5 \$ a) M' Q3 u! ]) d& h/ d; m
1 K( O4 e% w( }& Z, D. m2、Spring的transactionAttributes
1 k/ G# p1 c$ l; m7 l3 D0 a! x6 b* {2 K/ x+ l! j: X
2 X0 I' F) ~2 G! b
* B7 r8 }3 a& D& R2 u
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 + g' ?. x( L, a9 X+ r3 N( ?) w
d+ V/ l2 S8 [7 r% B v/ W Q' E
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 3 E# ^* h9 d+ L* d3 Z
8 A9 E; T7 {; n; D! n; x8 [
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 4 _" |) ?) K3 X7 [9 o6 A# o& ?
2 ^4 X" ^: B, O# s/ p! [; tPROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 / t; N) ?% E; v" a
* a" d+ E# n$ e% fPROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 8 `6 G+ Z+ s5 y# A
0 T6 L ^! H, }# i; R
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
+ h3 m( j' O+ o) P8 I" y
" y$ l( S2 |( m/ q W" l% p, l! v% KPROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 |
|