} } }

    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[]类型,默认为空数组。

    无论对感情还是对生活,“只要甜不要苦”都是任性而孩子气的,因为我们也不完美,我们也会伤害人。正因为我们都不完美,也因为生活从不是事事如意,所以对这些“瑕疵”的收纳才让我们对生活、对他人的爱变得日益真实而具体。—— 汪冰《世界再亏欠你,也要敢于拥抱幸福》
    分享到: