软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 架构设计 -> Spring+JDBC的简单配置和开发 -> 正文阅读
架构设计 最新文章
Opengl教程之读取obj并绘制在picturecontro
读《企业应用架构模式》第五章并发
StepbyStepintoSpring(IOC)
设计模式(2)用例图之一
使用实体组件系统(ECS)开发”吃方块”游戏实
编程学习之简单工厂模式与策略模式
Invalidprojectdescription.
基于Redis实现分布式消息队列(2)
《开源框架那点事儿15》:借船下海还是造船
原型模式——浅复制和深复制

[架构设计]Spring+JDBC的简单配置和开发

  2016-04-01 16:51:43

目前很多的公司采用了spring+jdbc的配置开发项目,下面介绍怎么配置环境到开发时候的注意事项:
①引入必要的jar文件
JDBC驱动(mysql为例):
mysql-connector-5.1.7.jar
数据库连接池(dbcp为例):
commons-dbcp.jar
commons-pool.jar
spring核心必须包:
spring.jar
commons-logging.jar
AOP非必须(方便使用建议添加):
cglib-nodep-2.1_3.jar
aspectjrt.jar
注解(一般都会使用):
common-annotations.jar
aspectjweaver.jar

一、配置数据源dataSource:
学过了spring后,这里采用spring容器管理来实例化数据源,一般在配置之前都会开启事务管理的命名空间,一般都会使用事务管理。
在配置一个工程的时候一定要注意的是循序渐进,不要一口气全部配置好所有的东西,这样如果经验不丰富的朋友,可能难以解决现有的报错。所以在配置好数据源的时候测试一下这个数据源是否正确,如果经验比较丰富的可以多配置几步再测试。
<?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:aop="http://www.springframework.org/schema/aop"
       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/schema/context/spring-context-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/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

        <!-- 开启注解 -->
        <context:annotation-config/>

        <!-- 配置数据连接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <property name="url" value="jdbc:mysql:///test?useUnicode=true&amp;characterEncoding=UTF-8"></property>
            <property name="driverClassName" value="org.gjt.mm.mysql.Driver"></property>
            <property name="username" value="root"></property>
            <property name="password" value="heyingxxx"></property>

            <!-- 连接池初始值 -->
            <property name="initialSize" value="2"/>
            <!-- 连接池最大值 -->
            <property name="maxActive" value="100"/>
            <!-- 连接池最大空闲值 -->
            <property name="maxIdle" value="5"/>
            <!-- 连接池最小空闲值 -->
            <property name="minIdle" value="2"/>
        </bean>
</beans>

这个dataSource已经交给spring容器管理了,现在使用spring实例化这个bean,以前介绍过方法:
public void testSave() throws Exception {
        try {
            AbstractApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//          PersonService personService = (PersonService) context.getBean("personService");
            DataSource dataSource = (DataSource) context.getBean("dataSource");
//          personService.save(new Person("heying", 2));
            System.out.println(dataSource.getConnection());
            context.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


二、配置业务bean,这边模拟一个员工的录入,简化操作,user只有两个属性,id和name
Person.java:
package com.heying.bean;

public class Person {
    private String name;
    private Integer id;

    // 初始化person
    public Person(String name, Integer id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
}

PersonService接口:
package com.heying.service;

import java.util.List;

import com.heying.bean.Person;
public interface PersonService {
    public void save(Person person);
    public void update(Integer id,Person person);
    public List<Person> findAll();
}

PersonService接口的实现类:
业务层面需要调用到数据库,所以需要将dataSource注入到PersonServiceBean,在dataSource无法直接实现数据的增删改查,如果这里只是单单的把数据库注入到PersonServiceBean显得有些不足,需要通过getConnection等大量的重复动作, 所以在JdbcTemplate中有很多现有的方法,这样就需要在使用PersonServiceBean的时候不仅需要注入dataSource,还需要初始化JdbcTemplate,这边可以使用两个或者多个方式。第一种是前面介绍的在业务bean->PersonServiceBean初始化时候注入dataSource时候采用setter方式,在setter中new JdbcTemplate(dataSource),还有一种就是在实例化业务bean->PersonServiceBean的时候使用init方法,值得注意的是,一定在注入了dataSource之后初始化JdbcTemplate,否则dataSource为null将报错,因为JdbcTemplate需要数据源初始化。这边采用init初始化:
package com.heying.service.impl;

import java.util.List;
import javax.annotation.Resource;
import javax.sql.DataSource;

import com.heying.bean.Person;
import com.heying.service.PersonService;

    public class PersonServiceBean implements PersonService{
        @Resource
        private DataSource dataSource; //注入dataSource到PersonServiceBean
        private JdbcTemplate jdbcTemplate ; // 可以使用init方法初始化,也可以在bean.xml中配置使用setter方法注入PersonServiceBean时候初始化

        public void init(){
        jdbcTemplate = new JdbcTemplate(dataSource);
        }

        @Override
        public void save(Person person) {
            try {
                System.out.println(dataSource.getConnection());
                System.out.println(jdbcTemplate);
                jdbcTemplate.update("insert into t_user (name,id) values (?,?) ", 
                    new Object[]{person.getName(),person.getId()},
                    new int[]{Types.VARCHAR,Types.INTEGER});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void update(Integer id, Person person) {

        }

        @Override
        public List<Person> findAll() {
            return null;
        }
}

bean.xml文件:
<bean id="personService" class="com.heying.service.impl.PersonServiceBean" init-method="init"></bean>

测试:
@Test
    public void testSave() throws Exception {
        try {
            AbstractApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            PersonService personService = (PersonService) context.getBean("personService");
            personService.save(new Person("heying51123", 1102));
            context.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

结果:

数据库:

基于注解的事务管理器:
这样就能完成了一个完整的过程,但是在企业开发中还必须使用事务管理,所以,还必须配置事务管理,防止异常发生时同一个事务中所有的操作回滚,这里注意的是在spring中的事务管理,默认只回滚RuntimeException()的异常,这类异常不能通过捕获处理,所以就不需要捕获的异常是特殊的Exception的子类(unchecked Exception),而其他的异常也是Exception的子类,这些属于检查异常,默认是不回滚事务的,所以需要在回滚的方法上定义   @Transactional(rollbackFor=Exception.class):

bean.xml文件:
事务管理的命名空间已经引入,要想使事务交给spring管理,需要和注解一样需要注册事务管理器,初始化时就需要将dataSource注入到txManager,交给事务管理器管理
        <!-- 注册事务管理器 -->
        <tx:annotation-driven transaction-manager="txManager"/>

        <!-- 配置事务管理器 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

第一次使用insert插入重复主键看看数据库是否回滚:
save方法:
    @Override
    public void save(Person person) throws Exception{
        try {
            System.out.println(dataSource.getConnection());
            System.out.println(jdbcTemplate);
            int updateRows = jdbcTemplate.update("insert into t_user (name,id) values (?,?) ", 
                    new Object[]{person.getName(),person.getId()},
                    new int[]{Types.VARCHAR,Types.INTEGER});
            int updateRows2 = jdbcTemplate.update("insert into t_user (name,id) values (?,?) ", 
                    new Object[]{person.getName(),person.getId()},
                    new int[]{Types.VARCHAR,Types.INTEGER});
            System.out.println("insert影响了: "+updateRows+ " ROWS");
        } catch (Exception e) {
            throw new Exception("普通捕获异常");
        }
    }

测试:
    public class TestCase {
    private static AbstractApplicationContext context;
    private static PersonService personService;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        context = new ClassPathXmlApplicationContext("bean.xml");
        personService = (PersonService) context.getBean("personService");
    }

    @Test
    public void testSave() throws Exception {
        try {
            personService.save(new Person("heying110", 1102));
        } catch (Exception e) {
            System.err.println("********异常********* "+e.getMessage()); 
        }finally{
            List<Person> list = personService.findAll();
            for (int i = 0; i < list.size(); i++) {
                System.out.println("##-->> "+list.get(i).getName());
                System.out.println("##-->> "+list.get(i).getId());
            }
            context.close();
        }
    }
}

结果:

总结: 显然第二条数据检查异常并没有影响第一条数据的插入
第二次加上@Transactional(rollbackFor=Exception.class)定义需要回滚的异常:
    @Transactional(rollbackFor=Exception.class)
    public void save(Person person) {
        fun()...
    }

测试:
personService.save(new Person("heying110", 1103));

结果:

1103没有插入,第二条记录出现异常,第一条就回滚了,一般数据库访问出现的异常比较基层,一般不可能通过try语句快解决的,这样也有的喜欢抛出一个运行期异常,不用指明@Transactional(rollbackFor=Exception.class)也能回滚所有出现异常的操作。
不是所有的访问都需要事务的,比如查询操作可以不适用事务管理,使用事务管理,必定会影响性能,所以介绍几种常见的事务传播属性(Propagation )的方式:
REQUIRES(默认):加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行,跟随调用的方法是否有事务决定。
PROPAGATION_MANDATORY:要求在一个已有的事务中执行,业务方法不能发起自己的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:不管业务没有没有事务,总会开启新事务,如果调用方法中存在事务,把当前事务挂起,新的事务会创建,直到方法结束后,新事务才算结束,原先挂起的事务恢复执行。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果被另外一个方法调用,且当前存在事务,就把当前事务挂起,调用方法结束后,原先事务在继续执行。
PROPAGATION_NEVER:要求在一个没有事务方式中执行,如果存在事务,则抛出异常,和MANDATORY相反。
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动的事务,则按照REQUIRES属性执行,它使用一个单独的事务,这个事务拥有多个回滚保存点,内部事务不会对外部事务产生影响,它只对DataSourceTransactionManager事务管理起效。
Spring事务隔离级别:
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED(读未提交): 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据,这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED:(读已提交) 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ(可重复读): 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读 ,它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生。
5. ISOLATION_SERIALIZABLE:(串行化) 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行, 除了防止脏读,不可重复读外,还避免了幻像读。
mysql数据隔离级别藏参考:

http://xm-king.iteye.com/blog/770721

介绍一下基于XML方式的事务管理,采用了AOP中的通知管理将事务交给spring管理
        <aop:config>
            <!-- 定义一个切面,拦截的包以及子包类任意类任意方法 -->
            <aop:pointcut id="transactionPointcut" expression="execution(* com.heying.service.PersonService..*.*(..))"/>
            <aop:advisor advice-ref="txtAdvice" pointcut-ref="transactionPointcut"/>
        </aop:config>
        <tx:advice id="txtAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/> <!-- get开头方法不使用 -->
                <tx:method name="*"/><!-- 其他方法,默认 propagation="REQUIRED" -->                
            </tx:attributes>
        </tx:advice>

上一篇文章      下一篇文章      查看所有文章
2016-04-01 16:50:07  
360图书馆 论文大全 母婴/育儿 软件开发资料 网页快照 文字转语音 购物精选 软件 美食菜谱 新闻中心 电影下载 小游戏 Chinese Culture
生肖星座解梦 三沣玩客 拍拍 视频 开发 Android开发 站长 古典小说 网文精选 搜图网 天下美图 中国文化英文 多播视频 装修知识库
2017-1-20 11:50:49
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --