zoukankan      html  css  js  c++  java
  • spring与jdbc整合

    spring+jdbc开发,我使用的是c3p0连接池

    1、数据库建表:

    create table person(
           id int primary key auto_increment,
           name varchar(30)
    )
    View Code

    2、配置数据源:

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClassName}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
            <property name="minPoolSize" value="${jdbc.minPoolSize"/>
            <property name="initialPoolSize" value="${jdbc.initialPoolSize"/>
            <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
            <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
        </bean>   

    我这里使用的是c3p0连接池,不同连接池对应的数据源的class是不一样的。我的配置信息存放在属性文件中。这里使用类似el表达式读取的属性文件。

    属性文件jdbc.properties:

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/customers?useUnicode=true&characterEncoding=UTF-8
    jdbc.username=guodaxia
    jdbc.password=961012gz
    jdbc.maxPoolSize=100
    jdbc.minPoolSize=10
    jdbc.initialPoolSize=20
    jdbc.maxIdleTime=600
    jdbc.acquireIncrement=5

    如何让spring容器加载属性文件使得我们可以直接使用呢?

    使用占位符指定属性文件:

    <context:property-placeholder location="classpath:jdbc.properties"/>

    这里用到了context,所以不要忘了加上context的namespace在声明中

    spring中使用事务:

    针对事务操作,我们需要引入事务有关的命名空间:

    xmlns:tx="http://www.springframework.org/schema/tx"
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

    然后我们要在配置文件中装载spring提供的事务管理器:

    <!-- 装载spring提供的针对数据源的事务管理器 -->
            <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
            </bean>

    1、使用注解方式使用事务

    前提:
    定义配置项(加入对应注解处理器):

    <tx:annotation-driven transaction-manager="txManager"/>

    使用:

    @Transactional 注解
    放在类上,类中的所有方法都开始被spring声明式事务管理。

    @Service("personService") @Transactional
    public class PersonServiceBean implements PersonService {

    只要该bean被spring容器管理,这样一声明该bean中的所有方法就会被spring事务管理器管理。

    关于事务管理的细节:

    默认的事务属性
    业务方法执行前,打开事务
    业务方法结束前,结束事务
    什么时候事务提交,什么时候事务回滚呢?
    默认情况下对于业务方法出现运行期异常RuntimeException,也叫checked异常,会进行事务的回滚
    如果业务方法出现Exception的话,默认的事务是不会滚的,Exception也叫checked异常

    限定异常类型是否回滚的属性
    noRollbackFor 指定不会滚的对应的异常类型
    rollbackFor 指定回滚对应的异常类型

    @Transactional(noRollbackFor=RuntimeException.class,rollbackFor=Exception.class)
    public void deletePerson(Integer personId) throws Exception{

    noRollbackForClassName和rollbackForClassName我就不说了

    事务传播属性(propagation):
    我们知道spring管理事务默认是方法开始前打开事务,结束后关闭事务。@Transactional注解放在类上,则该类的所有方法都具有事务特性。但我们有时候需要改变这种特性,
    比如:我的查询方法不希望开启和打开事务,这时怎么办呢?
    我们需要使用@Transactional注解的另一个属性propagation。


    属性值以及对应的意义:
    REQUIRED:
    业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务。这是spring默认的事务传播属性
    NOT_SUPPORT:
    声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便
    会恢复执行
    MANDATORY:
    该属性指定事务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务,如果业务方法没有在事务的环境下调用,容器就会抛出异常。
    SUPPORTS:
    这一属性表明,如果业务方法在某个事务范围内被调用,则方法称为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
    NEVER:
    指定业务方法绝对不能在事务范围内执行。如果业务放大在某个事务中执行,则容器会抛出异常,只有业务方法没有关联到任何事务,才能正常执行。
    NESTED:
    如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按REQUIRED属性执行,它使用了一个单独的事务,这个事务拥有多个可以回
    滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效果。外部事务的回滚会对内部事务造成影响,也要回滚。

    @Transactional(propagation=Propagation.NEVER)
    public void deletePerson(Integer personId){


    设置事务的等待时间:timeout属性

    设置事务的隔离级别(isolation)
    数据库系统提供了四种事务隔离级别
    Read Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)
    Read Commited:读已提交数据(会出现不可重复读和幻读)
    Repeatable Read:可重复读(会出现幻读,解决不可重复读的方式类似于镜像)
    Serializable:串行化

    脏读:
    一个事务读取到另一事务未提交的更新数据
    不可重读:
    在同一事务中,多次读取同一数据返回的结果有所不同。换句话说,后续读取可以读取到另一事务的更新数据。相反,“不可重复读”在同一事务中多次读取
    事务时,能够保证所读数据一样,也就是后续速去不能读取到另一事务已经提交的更新数据。
    幻读:
    一个事务读取到另一事务已经提交的insert数据

    @Transactional(isolation=Isolation.READ_COMMITTED)
    public void deletePerson(Integer personId){

    基于xml方式配置事务

    beans.xml中:

      <aop:config>
            <aop:pointcut expression="execution(* cn.itcast.service..*.*(..))" id="mycut"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="mycut"/>
        </aop:config>
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>

    检验事务是否成功管理:

    public void deletePerson(Integer personId){
            jdbcTemplate.update("delete from person where id=?", 
                    new Object[]{personId},
                    new int[]{java.sql.Types.INTEGER});
            
            jdbcTemplate.update("delete from personss where id=3");
        }

    第二条删除语句中表名有误,测试的时候如果spring管理了事务则两条sql语句都会回滚,也就是同一个事务,如果没有管理事务则只有一条sql语句回滚,所有第一条还是会
    删除数据库记录

    完整代码(部分被后面覆盖)

    package cn.itcast.service;
    
    import java.util.List;
    
    import cn.itcast.domain.Person;
    
    public interface PersonService {
        
        /**
         * 保存person
         * @param person
         */
        public void save(Person person);
        
        /**
         * 更新person
         * @param person
         */
        public void update(Person person);
        
        /**
         * 根据id获取person
         * @param personId
         * @return
         */
        public Person getPerson(Integer personId);
        
        /**
         * 获取所有person
         * @return
         */
        public List<Person> getPersons();
        
        /**
         * 根据id删除person
         * @param personId
         */
        public void deletePerson(Integer personId);
    }
    PersonService.java
    package cn.itcast.service.impl;
    
    import java.util.List;
    
    import javax.annotation.Resource;
    import javax.sql.DataSource;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import cn.itcast.domain.Person;
    import cn.itcast.service.PersonService;
    @Service("personService") @Transactional
    public class PersonServiceBean implements PersonService {
    
        
        private JdbcTemplate jdbcTemplate;
        
        public void save(Person person) {
            jdbcTemplate.update("insert into person(name) values(?)", 
                    new Object[]{person.getName()},
                    new int[]{java.sql.Types.VARCHAR});
        }
    
        public void update(Person person) {
            jdbcTemplate.update("update person set name=? where id=?",
                    new Object[]{person.getName(),person.getId()}, 
                    new int[]{java.sql.Types.VARCHAR,java.sql.Types.INTEGER});
        }
    
        public Person getPerson(Integer personId) {
            Person person = (Person) jdbcTemplate.queryForObject("select * from person where id=?",
                    new Object[]{personId},
                    new int[]{java.sql.Types.INTEGER},
                    new PersonRowMapper());
            return person;
        }
    
        public List<Person> getPersons() {
            @SuppressWarnings("unchecked")
            List<Person> persons=jdbcTemplate.query("select * from person", new PersonRowMapper());
            return persons;
        }
    
        public void deletePerson(Integer personId){
            jdbcTemplate.update("delete from person where id=?", 
                    new Object[]{personId},
                    new int[]{java.sql.Types.INTEGER});
            
            jdbcTemplate.update("delete from personss where id=3");
        }
    
        @Resource(name="dataSource")
        public void setDataSource(DataSource dataSource) {
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    
    
    }
    PersonServiceBean.java
    package cn.itcast.service.impl;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.springframework.jdbc.core.RowMapper;
    
    import cn.itcast.domain.Person;
    
    public class PersonRowMapper implements RowMapper{
    
        
        //外部调用我们方法的时候已经做了rs.next()操作
        public Object mapRow(ResultSet rs, int index) throws SQLException {
            Person person=new Person(rs.getInt("id"),rs.getString("name"));
            return person;
        }
    
    }
    PersonRowMapper.java
    package junit.test;
    
    
    import java.util.List;
    
    import org.junit.BeforeClass;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import cn.itcast.domain.Person;
    import cn.itcast.service.PersonService;
    
    public class PersonServiceBeanTest {
        
        private static PersonService personService;
    
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
            try{
                ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
                personService=(PersonService) ctx.getBean("personService");
            }catch(RuntimeException e){
                e.printStackTrace();
            }
            
        }
        
        @Test public void testSave(){
            for(int i=0;i<5;i++)
                personService.save(new Person("传智播客"+"7"));
        }
        @Test public void testUpdate(){
            Person person=personService.getPerson(1);
            person.setName("张三");
            personService.update(person);
        }
        @Test public void testDetetePerson(){
                personService.deletePerson(3);
        }
        @Test public void testgetPerson(){
            Person person=personService.getPerson(1);
            System.out.println(person.getId()+" "+person.getName());
        }
        
        @Test public void testFindAll(){
            List<Person> persons=personService.getPersons();
            if(persons!=null){
                for(Person person:persons){
                    System.out.println(person.getId()+" "+person.getName());
                }
            }
        }
    
    }
    PersonServiceBeanTest.java
    <?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:aop="http://www.springframework.org/schema/aop"
           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/aop
               http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context-2.5.xsd
               http://www.springframework.org/schema/tx
               http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
               
        <context:component-scan base-package="cn.itcast"/>
             
        <context:property-placeholder location="classpath:jdbc.properties"/>  
        
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClassName}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
            <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
            <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
            <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
            <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
        </bean>   
        
        <!-- 装载spring提供的针对数据源的事务管理器 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        
        <!-- 打开注解配置管理事务的处理器 -->
        <tx:annotation-driven transaction-manager="txManager"/>
        
          
        <aop:config>
            <aop:pointcut expression="execution(* cn.itcast.service..*.*(..))" id="mycut"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="mycut"/>
        </aop:config>
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>
                
    </beans>
    beans.xml
  • 相关阅读:
    检验Excel中数据是否与数据库中数据重复
    C# 上传文件
    asp.net Excel导入和导出
    完整ASP.Net Excel导入
    C#遍历指定文件夹中的所有文件
    C#获取文件夹下的所有文件的文件名
    UITextField 文本框 只能输入数字 且保留2位小数 实现
    Asp.Net生成无限级菜单
    给Repeater增加button事件,并绑定值
    简洁的Asp.net菜单控件
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/5914417.html
Copyright © 2011-2022 走看看