Spring-4-数据库连接池、JDBC Template、事务控制

# 内容
    1. 数据库连接池
        * 概念、作用
        * C3P0
        * Druid
        * 自定义JDBC工具类
    2. Spring JDBC : JDBC Template
    3. Srping中的事务控制


## 数据库连接池
    1. 概念:其实就是一个容器(集合),存放数据库连接的容器。
            当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
    2. 作用:
        1. 节约资源
        2. 用户访问高效
    3. 实现:
        1. 标准接口:DataSource   javax.sql包下的
            1. 方法:
                * 获取连接:getConnection()
                * 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

        2. 一般我们不去实现它,有数据库厂商来实现
            1. C3P0:数据库连接池技术
            2. Druid:数据库连接池实现技术,由阿里巴巴提供的
    4. C3P0:数据库连接池技术
        * 步骤:
            1. 导入jar包 (两个) c3p0-0.9.5.2.jar  和  mchange-commons-java-0.2.12.jar ,
                * 注意:不要忘记导入数据库驱动jar包
            2. 定义配置文件:
                * 名称: c3p0.properties 或者 c3p0-config.xml
                * 路径:直接将文件放在src目录下即可。
            3. 创建核心对象:数据库连接池对象 new ComboPooledDataSource()
            4. 获取连接: getConnection
        * 代码:

            //1.创建数据库连接池对象
            DataSource ds  = new ComboPooledDataSource();
            //2. 获取连接对象
            Connection conn = ds.getConnection();

    5. Druid:数据库连接池实现技术,由阿里巴巴提供的
        * 步骤:
            1. 导入jar包 druid-1.0.9.jar
            2. 定义配置文件:
                * 是properties形式的
                * 可以叫任意名称,可以放在任意目录下
            3. 加载配置文件。Properties
            4. 获取数据库连接池对象:通过工厂来获取  DruidDataSourceFactory.creatDateSource(properties参数名称)
            5. 获取连接:通过数据库连接池来获取 DataSource.getConnection
        * 代码:

             //3.加载配置文件
            Properties pro = new Properties();
            InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(is);
            //4.获取连接池对象
            DataSource ds = DruidDataSourceFactory.createDataSource(pro);
            //5.获取连接
            Connection conn = ds.getConnection();

    6. Spring内置的数据源

    7. 定义JDBC工具类
        1. 定义一个类 JDBCUtils
        2. 提供静态代码块加载配置文件,初始化连接池对象
        3. 提供方法
            1. 获取连接方法:通过数据库连接池获取连接
            2. 释放资源
            3. 获取连接池的方法
        * 代码:

            public class JDBCUtils {

                //1.定义成员变量 DataSource
                private static DataSource ds ;
            
                static{
                    try {
                        //1.加载配置文件
                        Properties pro = new Properties();
                        pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
                        //2.获取DataSource
                        ds = DruidDataSourceFactory.createDataSource(pro);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            
                /**
                 * 获取连接
                 */
                public static Connection getConnection() throws SQLException {
                    return ds.getConnection();
                }
            
                /**
                 * 释放资源
                 */
                public static void close(Statement stmt,Connection conn){
                   /* if(stmt != null){
                        try {
                            stmt.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
            
                    if(conn != null){
                        try {
                            conn.close();//归还连接
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }*/
            
                   close(null,stmt,conn);
                }
            
            
                public static void close(ResultSet rs , Statement stmt, Connection conn){
                    if(rs != null){
                        try {
                            rs.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
            
                    if(stmt != null){
                        try {
                            stmt.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
            
                    if(conn != null){
                        try {
                            conn.close();//归还连接
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            
                /**
                 * 获取连接池方法
                 */
            
                public static DataSource getDataSource(){
                    return  ds;
                }
            
            }


## Spring JDBC
    * 概念:Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
    * 使用步骤:
        1. 导入jar包
            * spring-jdbc-5.0.2.RELEASE.jar 
            * spring-tx-5.0.2.RELEASE.jar(与事务相关)
        2. 创建JdbcTemplate对象。依赖于数据源DataSource
            * JdbcTemplate template = new JdbcTemplate(DataSource ds);
        3. 调用JdbcTemplate的方法来完成CRUD的操作
            * update():执行DML语句。增、删、改语句
            * queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
                * 注意:这个方法查询的结果集长度只能是1
            * queryForList():查询结果将结果集封装为list集合
                * 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
            * query():查询结果,将结果封装为JavaBean对象
                * query的参数:RowMapper
                    * 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
                    * new BeanPropertyRowMapper<类型>(类型.class)
            * queryForObject:查询结果,将结果封装为对象
                * 注意:一般用于聚合函数的查询
        4. 练习:
            * 需求:
                1. 修改1号数据的 salary 为 10000
                2. 添加一条记录
                3. 删除刚才添加的记录
                4. 查询id为1的记录,将其封装为Map集合
                5. 查询所有记录,将其封装为List
                6. 查询所有记录,将其封装为Emp对象的List集合
                7. 查询总记录数

            * 代码:

                
                public class JdbcTemplateDemo2 {
                
                    //Junit单元测试,可以让方法独立执行
                
                
                    //1. 获取JDBCTemplate对象
                    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
                    /**
                     * 1. 修改1号数据的 salary 为 10000
                     */
                    @Test
                    public void test1(){
                
                        //2. 定义sql
                        String sql = "update emp set salary = 10000 where id = 1001";
                        //3. 执行sql
                        int count = template.update(sql);
                        System.out.println(count);
                    }
                
                    /**
                     * 2. 添加一条记录
                     */
                    @Test
                    public void test2(){
                        String sql = "insert into emp(id,ename,dept_id) values(?,?,?)";
                        int count = template.update(sql, 1015, "郭靖", 10);
                        System.out.println(count);
                
                    }
                
                    /**
                     * 3.删除刚才添加的记录
                     */
                    @Test
                    public void test3(){
                        String sql = "delete from emp where id = ?";
                        int count = template.update(sql, 1015);
                        System.out.println(count);
                    }
                
                    /**
                     * 4.查询id为1001的记录,将其封装为Map集合
                     * 注意:这个方法查询的结果集长度只能是1
                     */
                    @Test
                    public void test4(){
                        String sql = "select * from emp where id = ? or id = ?";
                        Map<String, Object> map = template.queryForMap(sql, 1001,1002);
                        System.out.println(map);
                        //{id=1001, ename=孙悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20}
                
                    }
                
                    /**
                     * 5. 查询所有记录,将其封装为List
                     */
                    @Test
                    public void test5(){
                        String sql = "select * from emp";
                        List<Map<String, Object>> list = template.queryForList(sql);
                
                        for (Map<String, Object> stringObjectMap : list) {
                            System.out.println(stringObjectMap);
                        }
                    }
                
                    /**
                     * 6. 查询所有记录,将其封装为Emp对象的List集合
                     */
                
                    @Test
                    public void test6(){
                        String sql = "select * from emp";
                        List<Emp> list = template.query(sql, new RowMapper<Emp>() {
                
                            @Override
                            public Emp mapRow(ResultSet rs, int i) throws SQLException {
                                Emp emp = new Emp();
                                int id = rs.getInt("id");
                                String ename = rs.getString("ename");
                                int job_id = rs.getInt("job_id");
                                int mgr = rs.getInt("mgr");
                                Date joindate = rs.getDate("joindate");
                                double salary = rs.getDouble("salary");
                                double bonus = rs.getDouble("bonus");
                                int dept_id = rs.getInt("dept_id");
                
                                emp.setId(id);
                                emp.setEname(ename);
                                emp.setJob_id(job_id);
                                emp.setMgr(mgr);
                                emp.setJoindate(joindate);
                                emp.setSalary(salary);
                                emp.setBonus(bonus);
                                emp.setDept_id(dept_id);
                
                                return emp;
                            }
                        });
                
                
                        for (Emp emp : list) {
                            System.out.println(emp);
                        }
                    }
                
                    /**
                     * 6. 查询所有记录,将其封装为Emp对象的List集合
                     */
                
                    @Test
                    public void test6_2(){
                        String sql = "select * from emp";
                        List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
                        for (Emp emp : list) {
                            System.out.println(emp);
                        }
                    }
                
                    /**
                     * 7. 查询总记录数
                     */
                
                    @Test
                    public void test7(){
                        String sql = "select count(id) from emp";
                        Long total = template.queryForObject(sql, Long.class);
                        System.out.println(total);
                    }
                
                }


## Spring中的事务控制
    1. API介绍
        1. PlatformTransactionManager 
            说明:PlatformTransactionManager接口提供事务操作的方法,包含有3个具体的操作
                * 获取事务状态信息
                    TransactionStatus getTransaction(TransactionDefinition definition)
                * 提交事务
                    void commit(TransactionStatus status)
                * 回滚事务
                    void rollback(TransactionStatus status)
            
            注意:我们在开发中都是使用它的实现类,真正管理事务的对象如下:
                * org.springframework.jdbc.datasource.DataSourceTransactionManager 
                    使用 Spring JDBC 或 iBatis 进行持久化数据时使用 
                * org.springframework.orm.hibernate5.HibernateTransactionManager  
                    使用 Hibernate 版本进行持久化数据时使用 
    
        2. TransactionDefinition 
            1. 说明:TransactionDefinition是事务的定义信息对象,有以下方法
                * 获取事务对象名称:String getName()
                * 获取事务隔离级:int getlsolationLevel()
                * 获取事务传播行为:int getPropagationBehavior()
                * 获取事务超时时间:int getTimeout()
                * 获取事务是否只读:boolean isReadOnly()

            2. 事务隔离级别:反映事务提交并发访问时的处理态度
                * ISOLATION DEFAULT:默认级别,归属下列某一种
                * ISOLATION_READ_UNCOMMITTED:可以读取未提交数据
                * ISOLATION READ COMMITTED:只能读取已提交数据,解决脏读问题(Oracle默认级别)
                * ISOLATION REPEATABLE_READ:是否读取其他事务提交修改后的数据,解决不可重复读问题(MySQL默认级别)
                * ISOLATION SERIALIZABLE:是否读取其他事务提交添加后的数据,解决幻影读问题

            3. 事务的传播行为
                * REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值) 
                * SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)

            4. 超时时间
                * 默认值是-1,没有超时限制。如果有,以秒为单位进行设置。 

            5. 是否是只读事务
                * 查询时一般设置为只读。

        3. TransactionStatus
            * 说明:TransactionStatus接口描述了某个时间点上事务对象的状态信息,包含有6个具体的操作
                * 刷新事务:void flush()
                * 获取是否是否存在存储点:boolean hasSavepoint()
                * 获取事务是否完成:boolean isCompleted()
                * 获取事务是否为新的事务:boolean isNewTransaction()
                * 获取事务是否回滚:boolean isRollbackOnly()
                * 设置事务回滚:void setRollbackOnly()


    2. 基于XML的声明式事务控制(配置方式)
        1. 环境搭建:
            1. 导入jar包:
            2. 创建 spring 的配置文件并导入约束 
                此处需要导入 aop 和 tx 两个名称空间 

                <?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:tx="http://www.springframework.org/schema/tx"
                      xsi:schemaLocation="http://www.springframework.org/schema/beans
                         http://www.springframework.org/schema/beans/spring-beans.xsd 
                       http://www.springframework.org/schema/tx
                         http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop  
                          http://www.springframework.org/schema/aop/spring-aop.xsd"> 
                 </beans>

            3. 准备数据库表和实体类 
            4. 编写service接口和实现类 
            5. 编写 Dao 接口和实现类 
            6. 在配置文件中配置业务层和持久层类

        2. 配置步骤:
            1. 配置事务管理器 

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"></property>
</bean>

            2. 配置事务的通知引用事务管理器 
                * 导入事务的约束 tx名称空间和约束,同时也需要aop的
                * 使用tx:advice标签配置事务通知
                    属性:
                           id:给事务通知起一个唯一标识
                           transaction-manager:给事务通知提供一个事务管理器引用

                <tx:advice id="txAdvice" transaction-manager="transactionManager">
                    <tx:attributes>
                        ...
                    </tx:attributes>
                </tx:advice>

            3. 配置事务的属性 
                * 在tx:advice下的tx:attributes标志配置事务属性
                *  配置事务的属性
                        name:指定方法的名称
                        isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
                        propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
                        read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
                        timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
                        rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
                        no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
 

                <tx:attributes>
                    <tx:method name="*" propagation="REQUIRED" read-only="false"/>
                    <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
                </tx:attributes>

            4. 配置 AOP 切入点表达式 
            5. 配置切入点表达式和事务通知的对应关系

                <!-- 配置aop-->
                <aop:config>
                    <!-- 配置切入点表达式-->
                    <aop:pointcut id="pt1" expression="execution(* com.lyp.service.impl.*.*(..))"></aop:pointcut>
                    <!--建立切入点表达式和事务通知的对应关系 -->
                    <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
                </aop:config>

            
            综合以上步骤,代码如下:
 

                <!-- 配置事务管理器 -->
                <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                    <property name="dataSource" ref="dataSource"></property>
                </bean>
            
                <!-- 配置事务的通知-->
                <tx:advice id="txAdvice" transaction-manager="transactionManager">
                    <tx:attributes>
                        <tx:method name="*" propagation="REQUIRED" read-only="false"/>
                        <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
                    </tx:attributes>
                </tx:advice>
            
                <!-- 配置aop-->
                <aop:config>
                    <!-- 配置切入点表达式-->
                    <aop:pointcut id="pt1" expression="execution(* com.lyp.service.impl.*.*(..))"></aop:pointcut>
                    <!--建立切入点表达式和事务通知的对应关系 -->
                    <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
                </aop:config>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值