安哥网络 发表于 2017-4-11 18:46:30

Java回顾之Spring基础

Java回顾之Spring基础
我计划分两到三篇文章来描述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简单示例  我们先来定义一个简单的接口和实现:http://common.cnblogs.com/images/copycode.gif
1 public interface UserDao { 2   void save(); 3 } 4 5 public class UserDaoImpl implements UserDao 6 { 7 8   public void save() { 9         System.out.println("save() is called.");10   }11 12 }http://common.cnblogs.com/images/copycode.gif

  然后是在classpath下创建一个beans.xml文件(这个文件名不是必须这样的):http://common.cnblogs.com/images/copycode.gif
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="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"      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                http://www.springframework.org/schema/context http://www.springframework.org/s ... ing-context-2.5.xsd                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">    <bean id="userDaoImpl" class = "sample.spring.ioc.UserDaoImpl"/></beans>    http://common.cnblogs.com/images/copycode.gif

  接下来是测试代码:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  输出结果如下:save() is called.
  我们还可以通过工厂方式来创建对象。  通过静态工厂创建Bean  添加一个类,如下:http://common.cnblogs.com/images/copycode.gif
1 public class UserDaoFactory {2 3   public static UserDao getUserDao()4   {5         return new UserDaoImpl();6   }7 }http://common.cnblogs.com/images/copycode.gif

  在beans.xml中,添加如下内容:1 <bean id="userDaoImpl2" class = "sample.spring.ioc.UserDaoFactory" factory-method = "getUserDao"/>
  测试代码和执行结果和上面类似,不再赘述。  通过实例工厂创建Bean  添加如下类:http://common.cnblogs.com/images/copycode.gif
1 public class UserDaoFactory2 2 {3   public UserDao getUserDao()4   {5         return new UserDaoImpl();6   }7 }http://common.cnblogs.com/images/copycode.gif

  这个类和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的设置不同。  下面是测试方法:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  执行结果如下:=====Singleton test=====userDao1A == userDao1B:true=====Prototype test=====userDao2A == userDao2B:false
  如何设置对象属性  上面的示例中,我们的对象中没有包含属性,对于业务对象来说,这一般是不现实。实际中的对象或多或少都会有一些属性。  Spring支持两种方式对属性赋值:set方式和构造函数。  下面我们会分别描述两种方式,但首先我们需要展示业务对象:http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifhttp://common.cnblogs.com/images/copycode.gif
1 public class UserServiceBean 2 { 3   private int userID; 4   private String userName; 5   private UserDao userDao; 6   private List<String> hobbies; 7   private Map<String, Integer> scores; 8    9   public UserServiceBean(int userID, String userName, UserDao userDao, List hobbies,Map scores)10   {11         this.userID = userID;12         this.userName = userName;13         this.userDao = userDao;14         this.hobbies = hobbies;15         this.scores = scores;16   }17   18   public UserServiceBean(){}19   20   public void setUserID(int userID) {21         this.userID = userID;22   }23   public int getUserID() {24         return userID;25   }26   public void setUserName(String userName) {27         this.userName = userName;28   }29   public String getUserName() {30         return userName;31   }32   public void setUserDao(UserDao userDao) {33         this.userDao = userDao;34   }35   public UserDao getUserDao() {36         return userDao;37   }38   public void setHobbies(List<String> hobbies) {39         this.hobbies = hobbies;40   }41   public List<String> getHobbies() {42         return hobbies;43   }44   public void setScores(Map<String, Integer> scores) {45         this.scores = scores;46   }47   public Map<String, Integer> getScores() {48         return scores;49   }50 }http://common.cnblogs.com/images/copycode.gif


  这是一个典型的学生信息,包括学号、姓名、爱好和成绩。  通过Set方式为对象属性赋值  我们在beans.xml中追加如内容:http://common.cnblogs.com/images/copycode.gif
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>http://common.cnblogs.com/images/copycode.gif

  上面是典型的为属性赋值的示例,其中属性不仅包括简单属性(整数、字符串),也包含了复杂属性(List、Map),还有IT论坛的bean。  下面是测试代码:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  输出结果如下:http://common.cnblogs.com/images/copycode.gif
编号:1姓名:张三爱好:羽毛球看电影弹吉他学习成绩:数据结构    90编译原理    85离散数学    82save() is called.http://common.cnblogs.com/images/copycode.gif

  通过构造函数为对象属性赋值  我们也可以通过构造函数来为对象赋值,在上面定义UserServiceBean时,我们已经添加了一个构造函数。下面来看beans.xml中的配置:http://common.cnblogs.com/images/copycode.gif
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>http://common.cnblogs.com/images/copycode.gif

  测试代码和输出结果同上。  需要注意:我们定义的业务对象应该保留默认的构造函数。  使用Annotation来定位Bean  在Spring中,除了在xml配置文件中定义对象,我们还可以使用Annotation来定位,这位我们提供了很大的方便。  这里我们使用的Annotation主要包括:@Resource/@Autowried/@Qualifier。  来看下面的示例:http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif Annotation示例
  测试方法:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  输出结果如下:save() is called.save() is called.sample.spring.ioc.UserDaoImplsave() 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 @Resource2 public void setUserDao2(UserDao userDao2) {3      this.userDao2 = userDao2;4 }
  这是作用在setter上的Annotation,@Resource 可以不写明name参数,这时Spring会首先按照名字然后按照数据类型的方式去定位bean。  自动加载对象定义  对于大型系统来说,我们可能会创建大量的类,如果这些类的声明都需要写在xml文件里的话,会产生额外大量的工作。  Spring提供了一种简单的机制让我们的对象可以自动注册。  我们可以在beans.xml中添加如下内容:1 <context:component-scan base-package="sample.spring.ioc"/>
  然后我们可以在sample.spring.ioc包下的对象,添加@Component/@Service/@Controller/@repository,这样Spring会自动将带有这些Annotation的类进行注册。  下面是一个示例:http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif 自动注册Bean示例
  这个类和上面定义的UserServiceBean2非常相似,需要注意在类前面添加的Annotation信息。  我们不需要在xml文件中手动定义这个bean,Spring会进行自动注册,注册的bean名称是userService。  AOP  我们在Java回顾之反射中已经设计了一个简单的AOP框架,通常情况下,对于AOP,我们有两种方式来实现。  使用DynamicProxy实现AOP  下面是一个简单的示例,首先定义业务对象:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  下面是一个实现了InvocationHandler的类:http://common.cnblogs.com/images/copycode.gif
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         else22         {23             System.out.println("The name is null.");24         }25         return result;26   }27 }http://common.cnblogs.com/images/copycode.gif

  接下来是测试代码:http://common.cnblogs.com/images/copycode.gif
1 private static void test1()2 {3   ProxyFactory pf = new ProxyFactory();4   UserDao userDao = (UserDao)pf.createUserDao(new UserDaoImpl());5   userDao.save();6 }http://common.cnblogs.com/images/copycode.gif

  执行结果如下:The name is null.
  这是因为userDao的类型是UserDao,它是一个接口,并没有定义name字段,因此name=null。  使用Cglib实现AOP  同样是上面的需求,我们假设并没有继承的接口,这我们可以使用cglib来实现。  首先我们重新定义一个UserDaoImpl2,它不会实现任何接口:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  然后是创建CglibFactory:http://common.cnblogs.com/images/copycode.gif
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         else21         {22             System.out.println("The name is null.");23         }24         return null;25   }26 }http://common.cnblogs.com/images/copycode.gif

  它实现了MethodInterceptor接口,其中包括intercept方法,这个方法就会通过反射的方式来触发目标方法,同时还可以添加一些IT论坛处理。  下面是测试方法:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  输出结果如下:The name is null.save() is called for Zhang San
  使用Spring实现AOP  Spring框架集合了ProxyFactory和Cglib两种方式来实现AOP。  我们来看一个示例,还是使用上面定义的UserDaoImpl以及UserDaoImpl2。  首先需要定义一个interceptor:http://common.cnblogs.com/images/copycode.gif
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 Throwable21   {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 }http://common.cnblogs.com/images/copycode.gif

  我们可以看到上面的代码中包含了一些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对象。  接下来是测试代码:http://common.cnblogs.com/images/copycode.gif
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 }http://common.cnblogs.com/images/copycode.gif

  这里我们可以看到,测试方法中既使用了UserDaoImpl1(这里是UserDao接口),也是用了UserDaoImpl2。正如我们上面所言,在Spring中,如果类实现了接口,Spring会按照ProxyFactory的方式来处理;如果没有实现接口,Spring会按照Cglib的方式来处理。  上面测试方法的输出如下:http://common.cnblogs.com/images/copycode.gif
BeforeBeforesave() is called for null执行时间:1The value is nullAfterAfter执行时间:1The value is nullBeforeBeforesave() is called for null执行时间:3001The value is nullAfterAfter执行时间:3002The value is nullBeforeThe name is Zhang SanBefore执行时间:26The value is nullAfterAfter执行时间:27The value is nullBeforeBefore执行时间:0The value is nullAfterAfter执行时间:1The value is nullhttp://common.cnblogs.com/images/copycode.gif

  使用Spring配置文件来配置AOP  上面的示例中,我们使用Annotation来配置AOP的信息,同样我们也可以使用xml文件的方式来配置AOP。  还是以上面定义的interceptor为基础,我们去掉里面所有的Annotation,然后在beans.xml中添加如下内容:http://common.cnblogs.com/images/copycode.gif
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>http://common.cnblogs.com/images/copycode.gif

  测试方法和输出结果同上。  Spring和JDBC  Spring中也包含了对JDBC数据访问的支持,它有一个JdbcTemplate的机制,其中提供了大量的API,对ResultSet进行了封装,可以大大简化我们的工作量。  同时Spring还提供了针对事务的支持,包含了一些Annotation,既可以作用在类上,也可以作用在方法上。  下面是一个简单的示例,我们还是连接MySQL数据库中的user表,实现对其CRUD操作。  首先是定义业务对象以及DAO接口:http://common.cnblogs.com/images/copycode.gif
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 public interface UserDao {20 21   void insertUser(User user);22   void updateUser(User user);23   void deleteUser(User user);24   List<User> getAllUser();25   User getUser(int id);26 }http://common.cnblogs.com/images/copycode.gif

  然后是建立一个Dao的实现类,这里使用了一些JdbcTemplate API:http://common.cnblogs.com/images/copycode.gif
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 deleteUser(User user) {13         jdbcTemplate.update("delete from 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("select * from user", 21                     new RowMapper()22                     {23                         public Object mapRow(ResultSet rs, int arg) throws SQLException24                         {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         try36         {37             return (User)jdbcTemplate.queryForObject("select * from 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 SQLException43                         {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 insertUser(User user) {60         jdbcTemplate.update("insert 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 updateUser(User user) {66         jdbcTemplate.update("update 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 }http://common.cnblogs.com/images/copycode.gif

  JdbcTemplate还提供了一些IT论坛的API,也非常实用。  接下来需要修改beans.xml:http://common.cnblogs.com/images/copycode.gif
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>http://common.cnblogs.com/images/copycode.gif

  这里theDataSource用来配置数据库连接信息;txManager来配置事务管理器的信息;userDao是我们的Dao实现类信息。  下面是测试方法:http://common.cnblogs.com/images/copycode.gif
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("=====insert user=====");12   User user = new User();13   user.setUserID(10);14   user.setUserName("Zhang Fei");15   userDao.insertUser(user);16   user = userDao.getUser(10);17   System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());18   System.out.println("=====update user=====");19   user.setUserName("Devil");20   userDao.updateUser(user);21   user = userDao.getUser(10);22   System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());23   System.out.println("=====delete user=====");24   userDao.deleteUser(user);25   user = userDao.getUser(10);26   if (user == null)27   {28         System.out.println("delete successfully.");29   }30 }http://common.cnblogs.com/images/copycode.gif

  输出结果如下:http://common.cnblogs.com/images/copycode.gif
MySQL-AB JDBC Driver=====get all user=====ID:1;Name:Zhang SanID:2;Name:TEST=====insert user=====ID:10;Name:Zhang Fei=====update user=====ID:10;Name:Devil=====delete user=====Incorrect result size: expected 1, actual 0delete successfully.http://common.cnblogs.com/images/copycode.gif

  说到数据库事务,我们在上面的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[]类型,默认为空数组。

    作者:李胜攀
    出处:http://wing011203.cnblogs.com/
http://www.cnblogs.com/wing011203/archive/2013/05/15/3078849.html
Java回顾之Spring基础
页: [1]
查看完整版本: Java回顾之Spring基础