Java回顾之Spring根蒂根基
添加时间:2013-5-15 点击量:
第一篇:Java回顾之I/O
第二篇:Java回顾之收集通信
第三篇:Java回顾之多线程
第四篇:Java回顾之多线程同步
第五篇:Java回顾之凑集
第六篇:Java回顾之序列化
第七篇:Java回顾之反射
第八篇:Java回顾之一些根蒂根基概念
第九篇:Java回顾之JDBC
第十篇:Java回顾之ORM框架
我规划分两到三篇文章来描述Spring,这一篇首要讲Spring一些根蒂根基的内容。
概述
我印象4、5年前,我还做java开辟的时辰,Spring是一个很是火的框架,尤其是在Web开辟范畴,和Struts以及Hibernate构成了SSH三剑客。当时Web开辟的另一个组合是LAMP,即Linux+Apache+MySQL+PHP,我在前端方面根蒂根基没有实战经验,对js等技巧也还是逗留在概念和语法方面,所以扬长避短,我对Spring以及Hibernate希罕感爱好。
昔时Spring是作为EJB的“调换者”横空出生避世的,其开创人Rod Johnson还写了一本《J2EE development without EJB》来履行这个框架,这也是一本关于Spring很经典的书,不过好是在接触Spring一段时候后再去浏览,结果会好一点。
Spring最首要的特点有两个:IoC和AOP,这也是J2EE开辟企业软件时经常碰着的题目:1)对象太多如何经管;2)共同逻辑和营业逻辑缠绕在一路,错综错杂,如何解耦。
这篇文章首要存眷3个方面:IoC、AOP和数据库接见。这里我们假设所有须要的jar都已经筹办伏贴。
IoC
IoC的全称是Inversion of Control,中文称为把握反转, Martin Flower由按照它发了然一个新词:Dependency Injection,中文称为依附注入。这两个词讲的是一回事儿。
IoC的本质是如何经管对象,传统意义上我们应用new体式格式来创建对象,但在企业应用开辟的过程中,多量的对象创定都在法度中保护很轻易造成资料浪费,并且晦气于法度的扩大。
实现IoC凡是有三种体式格式:
1)哄骗接口或者持续,一般以接口较多。这种实现体式格式和我们日常平凡提到的lazy load有异曲同工之妙。
2)机关函数注入。
3)属性注入。
IoC是Spring框架的核心,接下来我们来摸索一下Spring中IoC的风仪。
IoC简单示例
我们先来定义一个简单的接口和实现:
1 public interface UserDao {
2 void save();
3 }
4
5 public class UserDaoImpl implements UserDao
6 {
7 public void save() {
8 System.out.println(save() is called.);
9 }
10 }
然后是在classpath下创建一个beans.xml文件(这个文件名不是必须如许的):
1 <?xml version=1.0 encoding=UTF-8?>
2 <beans xmlns=http://www.springframework.org/schema/beans
3 xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
4 xmlns:context=http://www.springframework.org/schema/context
5 xmlns:tx=http://www.springframework.org/schema/tx
6 xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd>
9
10 <bean id=userDaoImpl class = sample.spring.ioc.UserDaoImpl/>
11 </beans>
接下来是测试代码:
1 private static void test1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/beans.xml);
4 UserDao userDao = (UserDao)ctx.getBean(userDaoImpl);
5 userDao.save();
6 }
输出成果如下:
save() is called.
我们还可以经由过程工厂体式格式来创建对象。
经由过程静态工厂创建Bean
添加一个类,如下:
1 public class UserDaoFactory {
2
3 public static UserDao getUserDao()
4 {
5 return new UserDaoImpl();
6 }
7 }
在beans.xml中,添加如下内容:
1 <bean id=userDaoImpl2 class = sample.spring.ioc.UserDaoFactory factory-method = getUserDao/>
测试代码和履行成果和上方类似,不再赘述。
经由过程实例工厂创建Bean
添加如下类:
public class UserDaoFactory2
{
public UserDao getUserDao()
{
return new UserDaoImpl();
}
}
这个类和UserDaoFactory独一的差别是这里的getUserDao是实例办法,而不是静态办法。
在beans.xml中追加如下内容:
1 <bean id=factory class=sample.spring.ioc.UserDaoFactory2/>
2 <bean id=userDaoImpl3 factory-bean=factory factory-method=getUserDao/>
测试办法和成果同上。
对象的生命周期
我们可以经由过程设置bean节点的scope属性来把握对象的声明周期,它包含两个可选值:
1)singleton,注解体系中对于同一个对象,只保存一个实例。
2)prototype,注解体系中每次获取bean时,都新建一个对象。
我们批改beans.xml文件:
1 <bean id=userDaoImpl class = sample.spring.ioc.UserDaoImpl scope=singleton/>
2 <bean id=userDaoImpl2 class = sample.spring.ioc.UserDaoImpl scope=prototype/>
这两个bean指向同一个类型,然则scope的设置不合。
下面是测试办法:
1 private static void scopeTest()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/scope.xml);
4 System.out.println(=====Singleton test=====);
5 UserDao userDao1A = (UserDao)ctx.getBean(userDaoImpl);
6 UserDao userDao1B = (UserDao)ctx.getBean(userDaoImpl);
7 System.out.println(userDao1A == userDao1B: + (userDao1A==userDao1B));
8 System.out.println(=====Prototype test=====);
9 UserDao userDao2A = (UserDao)ctx.getBean(userDaoImpl2);
10 UserDao userDao2B = (UserDao)ctx.getBean(userDaoImpl2);
11 System.out.println(userDao2A == userDao2B: + (userDao2A==userDao2B));
12 }
履行成果如下:
=====Singleton test=====
userDao1A == userDao1B:true
=====Prototype test=====
userDao2A == userDao2B:false
如何设置对象属性
上方的示例中,我们的对象中没有包含属性,对于营业对象来说,这一般是不实际。实际中的对象或多或少都邑有一些属性。
Spring支撑两种体式格式对属性赋值:set体式格式和机关函数。
下面我们会分别描述两种体式格式,但起首我们须要显现营业对象:
定义UserServiceBean
这是一个典范的学生信息,包含学号、姓名、爱好和成绩。
经由过程Set体式格式为对象属性赋值
我们在beans.xml中追加如内容:
1 <bean id=userService class=sample.spring.ioc.UserServiceBean>
2 <property name=userID value=1/>
3 <property name=userName value=张三/>
4 <property name=userDao ref=userDaoImpl/>
5 <property name=hobbies>
6 <list>
7 <value>羽毛球</value>
8 <value>看电影</value>
9 <value>弹吉他</value>
10 </list>
11 </property>
12 <property name=scores>
13 <map>
14 <entry key=数据布局 value=90/>
15 <entry key=编译道理 value=85/>
16 <entry key=离散数学 value=82/>
17 </map>
18 </property>
19 </bean>
上方是典范的为属性赋值的示例,此中属性不仅包含简单属性(整数、字符串),也包含了错杂属性(List、Map),还有其他的bean。
下面是测试代码:
1 private static void propertyTest1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/beans.xml);
4 UserServiceBean userService = (UserServiceBean)ctx.getBean(userService);
5 printUserService(userService);
6 }
7
8 private static void printUserService(UserServiceBean userService)
9 {
10 System.out.println(编号: + userService.getUserID());
11 System.out.println(姓名: + userService.getUserName());
12 System.out.println(爱好:);
13 for(String hobby:userService.getHobbies())
14 {
15 System.out.println(hobby);
16 }
17 System.out.println(进修成绩:);
18 for(Entry<String,Integer> entry:userService.getScores().entrySet())
19 {
20 System.out.println(entry.getKey() + \t + entry.getValue());
21 }
22 userService.getUserDao().save();
23 }
输出成果如下:
编号:1
姓名:张三
爱好:
羽毛球
看电影
弹吉他
进修成绩:
数据布局 90
编译道理 85
离散数学 82
save() is called.
经由过程机关函数为对象属性赋值
我们也可以经由过程机关函数来为对象赋值,在上方定义UserServiceBean时,我们已经添加了一个机关函数。下面来看beans.xml中的设备:
1 <bean id=userService2 class=sample.spring.ioc.UserServiceBean>
2 <constructor-arg index=0 value=1/>
3 <constructor-arg index=1 value=张三/>
4 <constructor-arg index=2 ref=userDaoImpl/>
5 <constructor-arg index=3>
6 <list>
7 <value>羽毛球</value>
8 <value>看电影</value>
9 <value>弹吉他</value>
10 </list>
11 </constructor-arg>
12 <constructor-arg index=4>
13 <map>
14 <entry key=数据布局 value=90/>
15 <entry key=编译道理 value=85/>
16 <entry key=离散数学 value=82/>
17 </map>
18 </constructor-arg>
19 </bean>
测试代码和输出成果同上。
须要重视:我们定义的营业对象应当保存默认的机关函数。
应用Annotation来定位Bean
在Spring中,除了在xml设备文件中定义对象,我们还可以应用Annotation来定位,这位我们供给了很大的便利。
这里我们应用的Annotation首要包含:@Resource/@Autowried/@Qualifier。
来看下面的示例:
Annotation示例
测试办法:
1 private static void annotationTest()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/annotation.xml);
4 UserServiceBean2 userService = (UserServiceBean2)ctx.getBean(userService);
5
6 userService.test();
7 }
输出成果如下:
save() is called.
save() is called.
sample.spring.ioc.UserDaoImpl
save() is called.
我们来对上方示例中呈现的Annotation来进行申明。
1 @Resource(name=userDaoImpl)
2 private UserDao userDao1;
这是定义在字段上的Annotation,是指userDao1应用xml设备文件中定义的名为“userDaoImpl”的bean进行填充。
1 @Autowired(required=false)
2 @Qualifier(userDaoImpl)
3 private UserDao userDao3;
这是第二种类型的Annotation,它把Autowired和Qualifier组合在一路应用,Qualifier来设置bean的名称,Autowired来设置bean找不到时的行动,required为true时会抛出异常,required为false时会返回null。
1 @Resource
2 public void setUserDao2(UserDao userDao2) {
3 this.userDao2 = userDao2;
4 }
这是感化在setter上的Annotation,@Resource 可以不写明name参数,这时Spring会起首遵守名字然后遵守数据类型的体式格式去定位bean。
主动加载对象定义
对于大型体系来说,我们可能会创建多量的类,若是这些类的声明都须要写在xml文件里的话,会产生额外多量的工作。
Spring供给了一种简单的机制让我们的对象可以主动注册。
我们可以在beans.xml中添加如下内容:
<context:component-scan base-package=sample.spring.ioc/>
然后我们可以在sample.spring.ioc包下的对象,添加@Component/@Service/@Controller/@repository,如许Spring会主动将带有这些Annotation的类进行注册。
下面是一个示例:
主动注册Bean示例
这个类和上方定义的UserServiceBean2很是类似,须要重视在类前面添加的Annotation信息。
我们不须要在xml文件中手动定义这个bean,Spring会进行主动注册,注册的bean名称是userService。
AOP
我们在Java回顾之反射中已经设计了一个简单的AOP框架,凡是景象下,对于AOP,我们有两种体式格式来实现。
应用DynamicProxy实现AOP
下面是一个简单的示例,起首定义营业对象:
1 public interface UserDao {
2
3 void save();
4 }
5
6 public class UserDaoImpl implements UserDao
7 {
8 private String name;
9
10 public void save() {
11 System.out.println(save() is called for + name);
12 }
13
14 public void setName(String name) {
15 this.name = name;
16 }
17
18 public String getName() {
19 return name;
20 }
21 }
下面是一个实现了InvocationHandler的类:
1 public class ProxyFactory implements InvocationHandler
2 {
3 private Object target;
4
5 public Object createUserDao(Object target)
6 {
7 this.target = target;
8 return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
9 this.target.getClass().getInterfaces(), this);
10 }
11
12 public Object invoke(Object proxy, Method method, Object[] args)
13 throws Throwable {
14
15 UserDaoImpl userDao = (UserDaoImpl)target;
16 Object result = null;
17 if(userDao.getName() != null)
18 {
19 result = method.invoke(target, args);
20 }
21 else
22 {
23 System.out.println(The name is null.);
24 }
25 return result;
26 }
27 }
接下来是测试代码:
1 private static void test1()
2 {
3 ProxyFactory pf = new ProxyFactory();
4 UserDao userDao = (UserDao)pf.createUserDao(new UserDaoImpl());
5 userDao.save();
6 }
履行成果如下:
The name is null.
这是因为userDao的类型是UserDao,它是一个接口,并没有定义name字段,是以name=null。
应用Cglib实现AOP
同样是上方的需求,我们假设并没有持续的接口,这我们可以应用cglib来实现。
起首我们从头定义一个UserDaoImpl2,它不会实现任何接口:
1 public class UserDaoImpl2
2 {
3 private String name;
4
5 public void save() throws InterruptedException {
6 Thread.sleep(3000);
7 System.out.println(save() is called for + name);
8 }
9
10 public void setName(String name) {
11 this.name = name;
12 }
13
14 public String getName() {
15 return name;
16 }
17
18 public void raiseException()
19 {
20 throw new RuntimeException(This is test.);
21 }
22 }
然后是创建CglibFactory:
1 public class CglibFactory implements MethodInterceptor
2 {
3 private Object target;
4 public Object createUserDao(Object target)
5 {
6 this.target = target;
7 Enhancer enhancer = new Enhancer();
8 enhancer.setSuperclass(target.getClass());
9 enhancer.setCallback(this);
10 return enhancer.create();
11 }
12
13 public Object intercept(Object proxy, Method method, Object[] args,
14 MethodProxy methodProxy) throws Throwable {
15 UserDaoImpl2 userDao = (UserDaoImpl2)target;
16 if (userDao.getName() != null)
17 {
18 return method.invoke(target, args);
19 }
20 else
21 {
22 System.out.println(The name is null.);
23 }
24 return null;
25 }
26 }
它实现了MethodInterceptor接口,此中包含intercept办法,这个办法就会经由过程反射的体式格式来触发目标办法,同时还可以添加一些其他处理惩罚。
下面是测试办法:
1 private static void test2() throws InterruptedException
2 {
3 CglibFactory cf = new CglibFactory();
4 UserDaoImpl2 temp = new UserDaoImpl2();
5 UserDaoImpl2 userDao = (UserDaoImpl2)cf.createUserDao(temp);
6 userDao.save();
7 temp.setName(Zhang San);
8 userDao = (UserDaoImpl2)cf.createUserDao(temp);
9 userDao.save();
10 }
输出成果如下:
The name is null.
save() is called for Zhang San
应用Spring实现AOP
Spring框架凑集了ProxyFactory和Cglib两种体式格式来实现AOP。
我们来看一个示例,还是应用上方定义的UserDaoImpl以及UserDaoImpl2。
起首须要定义一个interceptor:
1 @Aspect
2 public class MyInterceptor {
3
4 @Pointcut(execution ( sample.spring.aop..(..)))
5 public void anyMethod(){}
6
7 @Before(anyMethod())
8 public void before()
9 {
10 System.out.println(Before);
11 }
12
13 @After(anyMethod())
14 public void after()
15 {
16 System.out.println(After);
17 }
18
19 @Around(anyMethod())
20 public void Around(ProceedingJoinPoint pjp) throws Throwable
21 {
22 long start = System.currentTimeMillis();
23 pjp.proceed();
24 long end = System.currentTimeMillis();
25 System.out.println(履行时候: + (end - start));
26 }
27
28 @Before(anyMethod() && args(name))
29 public void before(String name)
30 {
31 System.out.println(The name is + name);
32 }
33
34 @AfterReturning(pointcut=anyMethod(), returning=result)
35 public void afterReturning(String result)
36 {
37 System.out.println(The value is + result);
38 }
39
40 @AfterThrowing(pointcut=anyMethod(), throwing=e)
41 public void afterThrowing(Exception e)
42 {
43 e.printStackTrace();
44 }
45 }
我们可以看到上方的代码中包含了一些Annotation,这些Annotation是用来实现AOP的关键。
然后须要批改beans.xml,添加如下内容:
1 <aop:aspectj-autoproxy />
2 <bean id=userDaoImpl class = sample.spring.aop.UserDaoImpl/>
3 <bean id=userDaoImpl2 class = sample.spring.aop.UserDaoImpl2/>
4 <bean id=myInterceptor class=sample.spring.aop.MyInterceptor/>
此中第一行是让Spring打开AOP的功能,下面三行定义了三个bean,这里我们把interceptor也看做是一个bean对象。
接下来是测试代码:
1 private static void test3() throws InterruptedException
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/aop/beans.xml);
4 UserDao userDao = (UserDao)ctx.getBean(userDaoImpl);
5 userDao.save();
6 UserDaoImpl2 userDao2 = (UserDaoImpl2)ctx.getBean(userDaoImpl2);
7 userDao2.save();
8 userDao2.setName(Zhang San);
9 String name = userDao2.getName();
10 //userDao2.raiseException();
11 }
这里我们可以看到,测试办法中既应用了UserDaoImpl1(这里是UserDao接口),也是用了UserDaoImpl2。正如我们上方所言,在Spring中,若是类实现了接口,Spring会遵守ProxyFactory的体式格式来处理惩罚;若是没有实现接口,Spring会遵守Cglib的体式格式来处理惩罚。
上方测试办法的输出如下:
Before
Before
save() is called for null
履行时候:1
The value is null
After
After
履行时候:1
The value is null
Before
Before
save() is called for null
履行时候:3001
The value is null
After
After
履行时候:3002
The value is null
Before
The name is Zhang San
Before
履行时候:26
The value is null
After
After
履行时候:27
The value is null
Before
Before
履行时候:0
The value is null
After
After
履行时候:1
The value is null
应用Spring设备文件来设备AOP
上方的示例中,我们应用Annotation来设备AOP的信息,同样我们也可以应用xml文件的体式格式来设备AOP。
还是以上方定义的interceptor为根蒂根基,我们去掉里面所有的Annotation,然后在beans.xml中添加如下内容:
1 <bean id=myInterceptor2 class=sample.spring.aop.MyInterceptor2/>
2 <aop:config>
3 <aop:aspect id=asp ref=myInterceptor2>
4 <aop:pointcut id=anyMethod expression=execution ( sample.spring.aop..(..))/>
5 <aop:before pointcut-ref=anyMethod method=before/>
6 <aop:after pointcut-ref=anyMethod method=after/>
7 <aop:around pointcut-ref=anyMethod method=around/>
8 <aop:after-returning pointcut-ref=anyMethod method=afterReturning returning=result/>
9 <aop:after-throwing pointcut-ref=anyMethod method=afterThrowing throwing=e/>
10 </aop:aspect>
11 </aop:config>
测试办法和输出成果同上。
Spring和JDBC
Spring中也包含了对JDBC数据接见的支撑,它有一个JdbcTemplate的机制,此中供给了多量的API,对ResultSet进行了封装,可以大大简化我们的工作量。
同时Spring还供给了针对事务的支撑,包含了一些Annotation,既可以感化在类上,也可以感化在办法上。
下面是一个简单的示例,我们还是连接MySQL数据库中的user表,实现对其CRUD操纵。
起首是定义营业对象以及DAO接口:
1 public class User {
2
3 private int userID;
4 private String userName;
5 public void setUserID(int userID) {
6 this.userID = userID;
7 }
8 public int getUserID() {
9 return userID;
10 }
11 public void setUserName(String userName) {
12 this.userName = userName;
13 }
14 public String getUserName() {
15 return userName;
16 }
17 }
18
19
20 public interface UserDao {
21
22 void User(User user);
23 void User(User user);
24 void User(User user);
25 List<User> getAllUser();
26 User getUser(int id);
27 }
然后是建树一个Dao的实现类,这里应用了一些JdbcTemplate API:
1 @Transactional
2 public class UserDaoImpl implements UserDao
3 {
4 private JdbcTemplate jdbcTemplate;
5
6 public void setDataSource(DataSource dataSource) throws SQLException
7 {
8 jdbcTemplate = new JdbcTemplate(dataSource);
9 System.out.println(dataSource.getConnection().getMetaData().getDriverName());
10 }
11
12 public void User(User user) {
13 jdbcTemplate.( user where id=?,
14 new Object[]{user.getUserID()},
15 new int[]{java.sql.Types.INTEGER});
16 }
17
18 @SuppressWarnings(unchecked)
19 public List<User> getAllUser() {
20 return (List<User>)jdbcTemplate.query( user,
21 new RowMapper()
22 {
23 public Object mapRow(ResultSet rs, int arg) throws SQLException
24 {
25 User user = new User();
26 user.setUserID(rs.getInt(ID));
27 user.setUserName(rs.getString(NAME));
28
29 return user;
30 }
31 });
32 }
33
34 public User getUser(int id) {
35 try
36 {
37 return (User)jdbcTemplate.queryForObject( user where id=?,
38 new Object[]{id},
39 new int[]{java.sql.Types.INTEGER},
40 new RowMapper()
41 {
42 public Object mapRow(ResultSet rs, int arg) throws SQLException
43 {
44 User user = new User();
45 user.setUserID(rs.getInt(id));
46 user.setUserName(rs.getString(name));
47 return user;
48 }
49 });
50 }
51 catch(Exception ex)
52 {
53 System.out.println(ex.getMessage());
54 }
55 return null;
56
57 }
58
59 public void User(User user) {
60 jdbcTemplate.( into user (id,name) values(?,?),
61 new Object[]{user.getUserID(), user.getUserName()},
62 new int[]{java.sql.Types.INTEGER, java.sql.Types.VARCHAR});
63 }
64
65 public void User(User user) {
66 jdbcTemplate.( user set name=? where id=?,
67 new Object[]{user.getUserName(), user.getUserID()},
68 new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
69 }
70
71 }
JdbcTemplate还供给了一些其他的API,也很是实用。
接下来须要批改beans.xml:
1 <bean id=theDatasource class=org.apache.commons.dbcp.BasicDataSource>
2 <property name=driverClassName value=com.mysql.jdbc.Driver />
3 <property name=url value=jdbc:mysql://localhost/test />
4 <property name=username value=root />
5 <property name=password value=123 />
6 <property name=initialSize value=2 />
7 <property name=maxActive value=100 />
8 <property name=maxIdle value=2 />
9 <property name=minIdle value=1 />
10 </bean>
11
12 <bean id=txManager class=org.springframework.jdbc.datasource.DataSourceTransactionManager>
13 <property name=dataSource ref=theDatasource />
14 </bean>
15
16 <tx:annotation-driven transaction-manager=txManager />
17
18 <bean id=userDao class=sample.spring.jdbc.UserDaoImpl>
19 <property name=dataSource ref=theDatasource/>
20 </bean>
这里theDataSource用来设备数据库连接信息;txManager来设备事务经管器的信息;userDao是我们的Dao实现类信息。
下面是测试办法:
1 public static void test1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/jdbc/beans.xml);
4 UserDao userDao = (UserDao)ctx.getBean(userDao);
5 System.out.println(=====get all user=====);
6 List<User> users = userDao.getAllUser();
7 for(User user:users)
8 {
9 System.out.println(ID: + user.getUserID() + ;Name: + user.getUserName());
10 }
11 System.out.println(===== user=====);
12 User user = new User();
13 user.setUserID(10);
14 user.setUserName(Zhang Fei);
15 userDao.User(user);
16 user = userDao.getUser(10);
17 System.out.println(ID: + user.getUserID() + ;Name: + user.getUserName());
18 System.out.println(===== user=====);
19 user.setUserName(Devil);
20 userDao.User(user);
21 user = userDao.getUser(10);
22 System.out.println(ID: + user.getUserID() + ;Name: + user.getUserName());
23 System.out.println(===== user=====);
24 userDao.User(user);
25 user = userDao.getUser(10);
26 if (user == null)
27 {
28 System.out.println( successfully.);
29 }
30 }
输出成果如下:
MySQL-AB JDBC Driver
=====get all user=====
ID:1;Name:Zhang San
ID:2;Name:TEST
===== user=====
ID:10;Name:Zhang Fei
===== user=====
ID:10;Name:Devil
===== user=====
Incorrect result size: expected 1, actual 0
successfully.
说到数据库事务,我们在上方的UserDaoImpl中可以看到,这个类的前面有一个名为@Transcational的Annotation声明,这是Spring实现事务的关键点,它既可以感化在类上,也可以感化在办法上。
@Transactional包含以下参数:
- propagation参数,Propagation类型(列举),默认值为Propogation.REQUIRED,支撑的值有REQUIRED、MANDATORY、NESTED、NEVER、NOT_SUPPORTED、REQUIRE_NEW、SUPPORTS。
- isolation参数,Isolation类型(列举),默认值为Isolation.DEFAULT,支撑的值有DEFAULT、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。
- timeout参数,int类型,事务的超不时候,默认值为-1,即不会超时。
- readOnly参数,boolean类型,true默示事务为只读,默认值为false。
- rollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
- rollbackForClassName参数,String[]类型,默认为空数组。
- noRollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
- noRollbackForClassName参数,String[]类型,默认为空数组。
无论对感情还是对生活,“只要甜不要苦”都是任性而孩子气的,因为我们也不完美,我们也会伤害人。正因为我们都不完美,也因为生活从不是事事如意,所以对这些“瑕疵”的收纳才让我们对生活、对他人的爱变得日益真实而具体。—— 汪冰《世界再亏欠你,也要敢于拥抱幸福》
第一篇:Java回顾之I/O
第二篇:Java回顾之收集通信
第三篇:Java回顾之多线程
第四篇:Java回顾之多线程同步
第五篇:Java回顾之凑集
第六篇:Java回顾之序列化
第七篇:Java回顾之反射
第八篇:Java回顾之一些根蒂根基概念
第九篇:Java回顾之JDBC
第十篇:Java回顾之ORM框架
我规划分两到三篇文章来描述Spring,这一篇首要讲Spring一些根蒂根基的内容。
概述
我印象4、5年前,我还做java开辟的时辰,Spring是一个很是火的框架,尤其是在Web开辟范畴,和Struts以及Hibernate构成了SSH三剑客。当时Web开辟的另一个组合是LAMP,即Linux+Apache+MySQL+PHP,我在前端方面根蒂根基没有实战经验,对js等技巧也还是逗留在概念和语法方面,所以扬长避短,我对Spring以及Hibernate希罕感爱好。
昔时Spring是作为EJB的“调换者”横空出生避世的,其开创人Rod Johnson还写了一本《J2EE development without EJB》来履行这个框架,这也是一本关于Spring很经典的书,不过好是在接触Spring一段时候后再去浏览,结果会好一点。
Spring最首要的特点有两个:IoC和AOP,这也是J2EE开辟企业软件时经常碰着的题目:1)对象太多如何经管;2)共同逻辑和营业逻辑缠绕在一路,错综错杂,如何解耦。
这篇文章首要存眷3个方面:IoC、AOP和数据库接见。这里我们假设所有须要的jar都已经筹办伏贴。
IoC
IoC的全称是Inversion of Control,中文称为把握反转, Martin Flower由按照它发了然一个新词:Dependency Injection,中文称为依附注入。这两个词讲的是一回事儿。
IoC的本质是如何经管对象,传统意义上我们应用new体式格式来创建对象,但在企业应用开辟的过程中,多量的对象创定都在法度中保护很轻易造成资料浪费,并且晦气于法度的扩大。
实现IoC凡是有三种体式格式:
1)哄骗接口或者持续,一般以接口较多。这种实现体式格式和我们日常平凡提到的lazy load有异曲同工之妙。
2)机关函数注入。
3)属性注入。
IoC是Spring框架的核心,接下来我们来摸索一下Spring中IoC的风仪。
IoC简单示例
我们先来定义一个简单的接口和实现:
1 public interface UserDao {
2 void save();
3 }
4
5 public class UserDaoImpl implements UserDao
6 {
7 public void save() {
8 System.out.println(save() is called.);
9 }
10 }
然后是在classpath下创建一个beans.xml文件(这个文件名不是必须如许的):
1 <?xml version=1.0 encoding=UTF-8?>
2 <beans xmlns=http://www.springframework.org/schema/beans
3 xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
4 xmlns:context=http://www.springframework.org/schema/context
5 xmlns:tx=http://www.springframework.org/schema/tx
6 xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd>
9
10 <bean id=userDaoImpl class = sample.spring.ioc.UserDaoImpl/>
11 </beans>
接下来是测试代码:
1 private static void test1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/beans.xml);
4 UserDao userDao = (UserDao)ctx.getBean(userDaoImpl);
5 userDao.save();
6 }
输出成果如下:
save() is called.
我们还可以经由过程工厂体式格式来创建对象。
经由过程静态工厂创建Bean
添加一个类,如下:
1 public class UserDaoFactory {
2
3 public static UserDao getUserDao()
4 {
5 return new UserDaoImpl();
6 }
7 }
在beans.xml中,添加如下内容:
1 <bean id=userDaoImpl2 class = sample.spring.ioc.UserDaoFactory factory-method = getUserDao/>
测试代码和履行成果和上方类似,不再赘述。
经由过程实例工厂创建Bean
添加如下类:
public class UserDaoFactory2
{
public UserDao getUserDao()
{
return new UserDaoImpl();
}
}
这个类和UserDaoFactory独一的差别是这里的getUserDao是实例办法,而不是静态办法。
在beans.xml中追加如下内容:
1 <bean id=factory class=sample.spring.ioc.UserDaoFactory2/>
2 <bean id=userDaoImpl3 factory-bean=factory factory-method=getUserDao/>
测试办法和成果同上。
对象的生命周期
我们可以经由过程设置bean节点的scope属性来把握对象的声明周期,它包含两个可选值:
1)singleton,注解体系中对于同一个对象,只保存一个实例。
2)prototype,注解体系中每次获取bean时,都新建一个对象。
我们批改beans.xml文件:
1 <bean id=userDaoImpl class = sample.spring.ioc.UserDaoImpl scope=singleton/>
2 <bean id=userDaoImpl2 class = sample.spring.ioc.UserDaoImpl scope=prototype/>
这两个bean指向同一个类型,然则scope的设置不合。
下面是测试办法:
1 private static void scopeTest()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/scope.xml);
4 System.out.println(=====Singleton test=====);
5 UserDao userDao1A = (UserDao)ctx.getBean(userDaoImpl);
6 UserDao userDao1B = (UserDao)ctx.getBean(userDaoImpl);
7 System.out.println(userDao1A == userDao1B: + (userDao1A==userDao1B));
8 System.out.println(=====Prototype test=====);
9 UserDao userDao2A = (UserDao)ctx.getBean(userDaoImpl2);
10 UserDao userDao2B = (UserDao)ctx.getBean(userDaoImpl2);
11 System.out.println(userDao2A == userDao2B: + (userDao2A==userDao2B));
12 }
履行成果如下:
=====Singleton test=====
userDao1A == userDao1B:true
=====Prototype test=====
userDao2A == userDao2B:false
如何设置对象属性
上方的示例中,我们的对象中没有包含属性,对于营业对象来说,这一般是不实际。实际中的对象或多或少都邑有一些属性。
Spring支撑两种体式格式对属性赋值:set体式格式和机关函数。
下面我们会分别描述两种体式格式,但起首我们须要显现营业对象:
这是一个典范的学生信息,包含学号、姓名、爱好和成绩。
经由过程Set体式格式为对象属性赋值
我们在beans.xml中追加如内容:
1 <bean id=userService class=sample.spring.ioc.UserServiceBean>
2 <property name=userID value=1/>
3 <property name=userName value=张三/>
4 <property name=userDao ref=userDaoImpl/>
5 <property name=hobbies>
6 <list>
7 <value>羽毛球</value>
8 <value>看电影</value>
9 <value>弹吉他</value>
10 </list>
11 </property>
12 <property name=scores>
13 <map>
14 <entry key=数据布局 value=90/>
15 <entry key=编译道理 value=85/>
16 <entry key=离散数学 value=82/>
17 </map>
18 </property>
19 </bean>
上方是典范的为属性赋值的示例,此中属性不仅包含简单属性(整数、字符串),也包含了错杂属性(List、Map),还有其他的bean。
下面是测试代码:
1 private static void propertyTest1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/beans.xml);
4 UserServiceBean userService = (UserServiceBean)ctx.getBean(userService);
5 printUserService(userService);
6 }
7
8 private static void printUserService(UserServiceBean userService)
9 {
10 System.out.println(编号: + userService.getUserID());
11 System.out.println(姓名: + userService.getUserName());
12 System.out.println(爱好:);
13 for(String hobby:userService.getHobbies())
14 {
15 System.out.println(hobby);
16 }
17 System.out.println(进修成绩:);
18 for(Entry<String,Integer> entry:userService.getScores().entrySet())
19 {
20 System.out.println(entry.getKey() + \t + entry.getValue());
21 }
22 userService.getUserDao().save();
23 }
输出成果如下:
编号:1
姓名:张三
爱好:
羽毛球
看电影
弹吉他
进修成绩:
数据布局 90
编译道理 85
离散数学 82
save() is called.
经由过程机关函数为对象属性赋值
我们也可以经由过程机关函数来为对象赋值,在上方定义UserServiceBean时,我们已经添加了一个机关函数。下面来看beans.xml中的设备:
1 <bean id=userService2 class=sample.spring.ioc.UserServiceBean>
2 <constructor-arg index=0 value=1/>
3 <constructor-arg index=1 value=张三/>
4 <constructor-arg index=2 ref=userDaoImpl/>
5 <constructor-arg index=3>
6 <list>
7 <value>羽毛球</value>
8 <value>看电影</value>
9 <value>弹吉他</value>
10 </list>
11 </constructor-arg>
12 <constructor-arg index=4>
13 <map>
14 <entry key=数据布局 value=90/>
15 <entry key=编译道理 value=85/>
16 <entry key=离散数学 value=82/>
17 </map>
18 </constructor-arg>
19 </bean>
测试代码和输出成果同上。
须要重视:我们定义的营业对象应当保存默认的机关函数。
应用Annotation来定位Bean
在Spring中,除了在xml设备文件中定义对象,我们还可以应用Annotation来定位,这位我们供给了很大的便利。
这里我们应用的Annotation首要包含:@Resource/@Autowried/@Qualifier。
来看下面的示例:
测试办法:
1 private static void annotationTest()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/ioc/annotation.xml);
4 UserServiceBean2 userService = (UserServiceBean2)ctx.getBean(userService);
5
6 userService.test();
7 }
输出成果如下:
save() is called.
save() is called.
sample.spring.ioc.UserDaoImpl
save() is called.
我们来对上方示例中呈现的Annotation来进行申明。
1 @Resource(name=userDaoImpl)
2 private UserDao userDao1;
这是定义在字段上的Annotation,是指userDao1应用xml设备文件中定义的名为“userDaoImpl”的bean进行填充。
1 @Autowired(required=false)
2 @Qualifier(userDaoImpl)
3 private UserDao userDao3;
这是第二种类型的Annotation,它把Autowired和Qualifier组合在一路应用,Qualifier来设置bean的名称,Autowired来设置bean找不到时的行动,required为true时会抛出异常,required为false时会返回null。
1 @Resource
2 public void setUserDao2(UserDao userDao2) {
3 this.userDao2 = userDao2;
4 }
这是感化在setter上的Annotation,@Resource 可以不写明name参数,这时Spring会起首遵守名字然后遵守数据类型的体式格式去定位bean。
主动加载对象定义
对于大型体系来说,我们可能会创建多量的类,若是这些类的声明都须要写在xml文件里的话,会产生额外多量的工作。
Spring供给了一种简单的机制让我们的对象可以主动注册。
我们可以在beans.xml中添加如下内容:
<context:component-scan base-package=sample.spring.ioc/>
然后我们可以在sample.spring.ioc包下的对象,添加@Component/@Service/@Controller/@repository,如许Spring会主动将带有这些Annotation的类进行注册。
下面是一个示例:
这个类和上方定义的UserServiceBean2很是类似,须要重视在类前面添加的Annotation信息。
我们不须要在xml文件中手动定义这个bean,Spring会进行主动注册,注册的bean名称是userService。
AOP
我们在Java回顾之反射中已经设计了一个简单的AOP框架,凡是景象下,对于AOP,我们有两种体式格式来实现。
应用DynamicProxy实现AOP
下面是一个简单的示例,起首定义营业对象:
1 public interface UserDao {
2
3 void save();
4 }
5
6 public class UserDaoImpl implements UserDao
7 {
8 private String name;
9
10 public void save() {
11 System.out.println(save() is called for + name);
12 }
13
14 public void setName(String name) {
15 this.name = name;
16 }
17
18 public String getName() {
19 return name;
20 }
21 }
下面是一个实现了InvocationHandler的类:
1 public class ProxyFactory implements InvocationHandler
2 {
3 private Object target;
4
5 public Object createUserDao(Object target)
6 {
7 this.target = target;
8 return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
9 this.target.getClass().getInterfaces(), this);
10 }
11
12 public Object invoke(Object proxy, Method method, Object[] args)
13 throws Throwable {
14
15 UserDaoImpl userDao = (UserDaoImpl)target;
16 Object result = null;
17 if(userDao.getName() != null)
18 {
19 result = method.invoke(target, args);
20 }
21 else
22 {
23 System.out.println(The name is null.);
24 }
25 return result;
26 }
27 }
接下来是测试代码:
1 private static void test1()
2 {
3 ProxyFactory pf = new ProxyFactory();
4 UserDao userDao = (UserDao)pf.createUserDao(new UserDaoImpl());
5 userDao.save();
6 }
履行成果如下:
The name is null.
这是因为userDao的类型是UserDao,它是一个接口,并没有定义name字段,是以name=null。
应用Cglib实现AOP
同样是上方的需求,我们假设并没有持续的接口,这我们可以应用cglib来实现。
起首我们从头定义一个UserDaoImpl2,它不会实现任何接口:
1 public class UserDaoImpl2
2 {
3 private String name;
4
5 public void save() throws InterruptedException {
6 Thread.sleep(3000);
7 System.out.println(save() is called for + name);
8 }
9
10 public void setName(String name) {
11 this.name = name;
12 }
13
14 public String getName() {
15 return name;
16 }
17
18 public void raiseException()
19 {
20 throw new RuntimeException(This is test.);
21 }
22 }
然后是创建CglibFactory:
1 public class CglibFactory implements MethodInterceptor
2 {
3 private Object target;
4 public Object createUserDao(Object target)
5 {
6 this.target = target;
7 Enhancer enhancer = new Enhancer();
8 enhancer.setSuperclass(target.getClass());
9 enhancer.setCallback(this);
10 return enhancer.create();
11 }
12
13 public Object intercept(Object proxy, Method method, Object[] args,
14 MethodProxy methodProxy) throws Throwable {
15 UserDaoImpl2 userDao = (UserDaoImpl2)target;
16 if (userDao.getName() != null)
17 {
18 return method.invoke(target, args);
19 }
20 else
21 {
22 System.out.println(The name is null.);
23 }
24 return null;
25 }
26 }
它实现了MethodInterceptor接口,此中包含intercept办法,这个办法就会经由过程反射的体式格式来触发目标办法,同时还可以添加一些其他处理惩罚。
下面是测试办法:
1 private static void test2() throws InterruptedException
2 {
3 CglibFactory cf = new CglibFactory();
4 UserDaoImpl2 temp = new UserDaoImpl2();
5 UserDaoImpl2 userDao = (UserDaoImpl2)cf.createUserDao(temp);
6 userDao.save();
7 temp.setName(Zhang San);
8 userDao = (UserDaoImpl2)cf.createUserDao(temp);
9 userDao.save();
10 }
输出成果如下:
The name is null.
save() is called for Zhang San
应用Spring实现AOP
Spring框架凑集了ProxyFactory和Cglib两种体式格式来实现AOP。
我们来看一个示例,还是应用上方定义的UserDaoImpl以及UserDaoImpl2。
起首须要定义一个interceptor:
1 @Aspect
2 public class MyInterceptor {
3
4 @Pointcut(execution ( sample.spring.aop..(..)))
5 public void anyMethod(){}
6
7 @Before(anyMethod())
8 public void before()
9 {
10 System.out.println(Before);
11 }
12
13 @After(anyMethod())
14 public void after()
15 {
16 System.out.println(After);
17 }
18
19 @Around(anyMethod())
20 public void Around(ProceedingJoinPoint pjp) throws Throwable
21 {
22 long start = System.currentTimeMillis();
23 pjp.proceed();
24 long end = System.currentTimeMillis();
25 System.out.println(履行时候: + (end - start));
26 }
27
28 @Before(anyMethod() && args(name))
29 public void before(String name)
30 {
31 System.out.println(The name is + name);
32 }
33
34 @AfterReturning(pointcut=anyMethod(), returning=result)
35 public void afterReturning(String result)
36 {
37 System.out.println(The value is + result);
38 }
39
40 @AfterThrowing(pointcut=anyMethod(), throwing=e)
41 public void afterThrowing(Exception e)
42 {
43 e.printStackTrace();
44 }
45 }
我们可以看到上方的代码中包含了一些Annotation,这些Annotation是用来实现AOP的关键。
然后须要批改beans.xml,添加如下内容:
1 <aop:aspectj-autoproxy />
2 <bean id=userDaoImpl class = sample.spring.aop.UserDaoImpl/>
3 <bean id=userDaoImpl2 class = sample.spring.aop.UserDaoImpl2/>
4 <bean id=myInterceptor class=sample.spring.aop.MyInterceptor/>
此中第一行是让Spring打开AOP的功能,下面三行定义了三个bean,这里我们把interceptor也看做是一个bean对象。
接下来是测试代码:
1 private static void test3() throws InterruptedException
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/aop/beans.xml);
4 UserDao userDao = (UserDao)ctx.getBean(userDaoImpl);
5 userDao.save();
6 UserDaoImpl2 userDao2 = (UserDaoImpl2)ctx.getBean(userDaoImpl2);
7 userDao2.save();
8 userDao2.setName(Zhang San);
9 String name = userDao2.getName();
10 //userDao2.raiseException();
11 }
这里我们可以看到,测试办法中既应用了UserDaoImpl1(这里是UserDao接口),也是用了UserDaoImpl2。正如我们上方所言,在Spring中,若是类实现了接口,Spring会遵守ProxyFactory的体式格式来处理惩罚;若是没有实现接口,Spring会遵守Cglib的体式格式来处理惩罚。
上方测试办法的输出如下:
Before
Before
save() is called for null
履行时候:1
The value is null
After
After
履行时候:1
The value is null
Before
Before
save() is called for null
履行时候:3001
The value is null
After
After
履行时候:3002
The value is null
Before
The name is Zhang San
Before
履行时候:26
The value is null
After
After
履行时候:27
The value is null
Before
Before
履行时候:0
The value is null
After
After
履行时候:1
The value is null
应用Spring设备文件来设备AOP
上方的示例中,我们应用Annotation来设备AOP的信息,同样我们也可以应用xml文件的体式格式来设备AOP。
还是以上方定义的interceptor为根蒂根基,我们去掉里面所有的Annotation,然后在beans.xml中添加如下内容:
1 <bean id=myInterceptor2 class=sample.spring.aop.MyInterceptor2/>
2 <aop:config>
3 <aop:aspect id=asp ref=myInterceptor2>
4 <aop:pointcut id=anyMethod expression=execution ( sample.spring.aop..(..))/>
5 <aop:before pointcut-ref=anyMethod method=before/>
6 <aop:after pointcut-ref=anyMethod method=after/>
7 <aop:around pointcut-ref=anyMethod method=around/>
8 <aop:after-returning pointcut-ref=anyMethod method=afterReturning returning=result/>
9 <aop:after-throwing pointcut-ref=anyMethod method=afterThrowing throwing=e/>
10 </aop:aspect>
11 </aop:config>
测试办法和输出成果同上。
Spring和JDBC
Spring中也包含了对JDBC数据接见的支撑,它有一个JdbcTemplate的机制,此中供给了多量的API,对ResultSet进行了封装,可以大大简化我们的工作量。
同时Spring还供给了针对事务的支撑,包含了一些Annotation,既可以感化在类上,也可以感化在办法上。
下面是一个简单的示例,我们还是连接MySQL数据库中的user表,实现对其CRUD操纵。
起首是定义营业对象以及DAO接口:
1 public class User {
2
3 private int userID;
4 private String userName;
5 public void setUserID(int userID) {
6 this.userID = userID;
7 }
8 public int getUserID() {
9 return userID;
10 }
11 public void setUserName(String userName) {
12 this.userName = userName;
13 }
14 public String getUserName() {
15 return userName;
16 }
17 }
18
19
20 public interface UserDao {
21
22 void User(User user);
23 void User(User user);
24 void User(User user);
25 List<User> getAllUser();
26 User getUser(int id);
27 }
然后是建树一个Dao的实现类,这里应用了一些JdbcTemplate API:
1 @Transactional
2 public class UserDaoImpl implements UserDao
3 {
4 private JdbcTemplate jdbcTemplate;
5
6 public void setDataSource(DataSource dataSource) throws SQLException
7 {
8 jdbcTemplate = new JdbcTemplate(dataSource);
9 System.out.println(dataSource.getConnection().getMetaData().getDriverName());
10 }
11
12 public void User(User user) {
13 jdbcTemplate.( user where id=?,
14 new Object[]{user.getUserID()},
15 new int[]{java.sql.Types.INTEGER});
16 }
17
18 @SuppressWarnings(unchecked)
19 public List<User> getAllUser() {
20 return (List<User>)jdbcTemplate.query( user,
21 new RowMapper()
22 {
23 public Object mapRow(ResultSet rs, int arg) throws SQLException
24 {
25 User user = new User();
26 user.setUserID(rs.getInt(ID));
27 user.setUserName(rs.getString(NAME));
28
29 return user;
30 }
31 });
32 }
33
34 public User getUser(int id) {
35 try
36 {
37 return (User)jdbcTemplate.queryForObject( user where id=?,
38 new Object[]{id},
39 new int[]{java.sql.Types.INTEGER},
40 new RowMapper()
41 {
42 public Object mapRow(ResultSet rs, int arg) throws SQLException
43 {
44 User user = new User();
45 user.setUserID(rs.getInt(id));
46 user.setUserName(rs.getString(name));
47 return user;
48 }
49 });
50 }
51 catch(Exception ex)
52 {
53 System.out.println(ex.getMessage());
54 }
55 return null;
56
57 }
58
59 public void User(User user) {
60 jdbcTemplate.( into user (id,name) values(?,?),
61 new Object[]{user.getUserID(), user.getUserName()},
62 new int[]{java.sql.Types.INTEGER, java.sql.Types.VARCHAR});
63 }
64
65 public void User(User user) {
66 jdbcTemplate.( user set name=? where id=?,
67 new Object[]{user.getUserName(), user.getUserID()},
68 new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
69 }
70
71 }
JdbcTemplate还供给了一些其他的API,也很是实用。
接下来须要批改beans.xml:
1 <bean id=theDatasource class=org.apache.commons.dbcp.BasicDataSource>
2 <property name=driverClassName value=com.mysql.jdbc.Driver />
3 <property name=url value=jdbc:mysql://localhost/test />
4 <property name=username value=root />
5 <property name=password value=123 />
6 <property name=initialSize value=2 />
7 <property name=maxActive value=100 />
8 <property name=maxIdle value=2 />
9 <property name=minIdle value=1 />
10 </bean>
11
12 <bean id=txManager class=org.springframework.jdbc.datasource.DataSourceTransactionManager>
13 <property name=dataSource ref=theDatasource />
14 </bean>
15
16 <tx:annotation-driven transaction-manager=txManager />
17
18 <bean id=userDao class=sample.spring.jdbc.UserDaoImpl>
19 <property name=dataSource ref=theDatasource/>
20 </bean>
这里theDataSource用来设备数据库连接信息;txManager来设备事务经管器的信息;userDao是我们的Dao实现类信息。
下面是测试办法:
1 public static void test1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(sample/spring/jdbc/beans.xml);
4 UserDao userDao = (UserDao)ctx.getBean(userDao);
5 System.out.println(=====get all user=====);
6 List<User> users = userDao.getAllUser();
7 for(User user:users)
8 {
9 System.out.println(ID: + user.getUserID() + ;Name: + user.getUserName());
10 }
11 System.out.println(===== user=====);
12 User user = new User();
13 user.setUserID(10);
14 user.setUserName(Zhang Fei);
15 userDao.User(user);
16 user = userDao.getUser(10);
17 System.out.println(ID: + user.getUserID() + ;Name: + user.getUserName());
18 System.out.println(===== user=====);
19 user.setUserName(Devil);
20 userDao.User(user);
21 user = userDao.getUser(10);
22 System.out.println(ID: + user.getUserID() + ;Name: + user.getUserName());
23 System.out.println(===== user=====);
24 userDao.User(user);
25 user = userDao.getUser(10);
26 if (user == null)
27 {
28 System.out.println( successfully.);
29 }
30 }
输出成果如下:
MySQL-AB JDBC Driver
=====get all user=====
ID:1;Name:Zhang San
ID:2;Name:TEST
===== user=====
ID:10;Name:Zhang Fei
===== user=====
ID:10;Name:Devil
===== user=====
Incorrect result size: expected 1, actual 0
successfully.
说到数据库事务,我们在上方的UserDaoImpl中可以看到,这个类的前面有一个名为@Transcational的Annotation声明,这是Spring实现事务的关键点,它既可以感化在类上,也可以感化在办法上。
@Transactional包含以下参数:
- propagation参数,Propagation类型(列举),默认值为Propogation.REQUIRED,支撑的值有REQUIRED、MANDATORY、NESTED、NEVER、NOT_SUPPORTED、REQUIRE_NEW、SUPPORTS。
- isolation参数,Isolation类型(列举),默认值为Isolation.DEFAULT,支撑的值有DEFAULT、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。
- timeout参数,int类型,事务的超不时候,默认值为-1,即不会超时。
- readOnly参数,boolean类型,true默示事务为只读,默认值为false。
- rollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
- rollbackForClassName参数,String[]类型,默认为空数组。
- noRollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
- noRollbackForClassName参数,String[]类型,默认为空数组。