1. 程式人生 > >Spring知識複習之三

Spring知識複習之三

Spring整合JDBC

1 Spring提供了很多持久層技術模板類

ORM持久化技術 模板類

       JDBC                             org.springframework.jdbc.core.JdbcTemplate
       Hibernate3.0             org.springframework.orm.hibernate3.HibernateTemplate
       IBatis(MyBatis)          org.springframework.orm.ibatis.SqlMapClientTemplate
       JPA                              org.springframework.orm.jpa.JpaTemplate

2 Spring與Jdbc

(1)原生JDBC模板
<1>連線池的使用
                1.使用C3p0連線池(com.mchange.v2.c3p0.ComboPooledDataSource)
                程式碼示例如下:
                    ComboPooledDataSource dataSource=new ComboPooledDataSource();
                    dataSource.setDriverClass("com.mysql.jdbc.Driver");
                    dataSource.setJdbcUrl("jdbc:mysql:///hibernate_crm");
                    dataSource.setUser("root");
                    dataSource.setPassword("root");
                2.使用spring內建連線池(org.springframework.jdbc.datasource.DriverManagerDataSource)
                程式碼示例如下:
                    DriverManagerDataSource dataSource=new DriverManagerDataSource();
                    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
                    dataSource.setUrl("jdbc:mysql:///hibernate_crm");
                    dataSource.setUsername("root");
                    dataSource.setPassword("root");
    <2>JDBC模板物件的呼叫
                    //1 建立JDBC模板物件
                    JdbcTemplate jt=new JdbcTemplate();
                    //2連線進連線池
                    jt.setDataSource(dataSource);
                    //3 書寫sql語句,並執行
                    String sql="insert into t_user values(null,'rose')";
                    jt.update(sql);
(2)Spring對連線池進行管理
                <1>配置Spring內建的連線池DriverManagerDataSource
                        <bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                                <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
                                <property name="url" value="jdbc:mysql:///hibernate_crm"></property>
                                <property name="username" value="root"></property>
                                <property name="password" value="root"></property>
                        </bean>
                        <!--配置JDBCTemplate物件並關聯Spring內建的連線池  -->
                        <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                            <property name="dataSource" ref="dataSource"></property>
                        </bean>
                <2>配置C3P0連線池
                         匯入jar包:    com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
                        <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
                            <property name="jdbcUrl" value="jdbc:mysql:///hibernate_crm"></property>
                            <property name="user" value="root"></property>
                            <property name="password" value="root"></property>
                        </bean>
                        <!--配置JDBCTemplate物件並關聯C3p0連線池 -->
                        <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                            <property name="dataSource" ref="dataSource"></property>
                        </bean>
                <3>配置db連線池
                        匯入jar包: 
                                com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
                                com.springsource.org.apache.commons.pool-1.5.3.jar
                                <!-- 配置 DBCP 連線池 -->
                                <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
                                <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
                                <property name="url" value="jdbc:mysql:///spring_day02"/>
                                <property name="username" value="root"/>
                                <property name="password" value="123"/>
                                </bean>
(3)JdbcTemplate物件的增刪改查
            概述:JdbcTemplate的增刪改都使用  update()方法。而查詢則使用queryForObject()
            //增
            @Override
            public void save(User u) {
                String sql="insert into t_user values(null,?)";
                jt.update(sql,u.getName());
            }
            //刪(根據id刪除)
            @Override
            public void delete(Integer id) {
                String sql="delete from t_user where id=?";
                jt.update(sql,id);
            }
            //改
            @Override
            public void update(User u) {
                String sql="update t_user set name=? where id=?";
                jt.update(sql,u.getName(),u.getId());
            }
            //查(根據id進行查詢,獲取一個物件)
            @Override
            public User getById(Integer id) {
                String sql="select * from t_user where id=?";
                User user = jt.queryForObject(sql, new RowMapper<User>() {
                    @Override
                    public User mapRow(ResultSet rs, int arg1) throws SQLException {
                        //封裝實體 User物件返回給這個方法
                        User u=new User();
                        u.setId(rs.getInt("id"));
                        u.setName(rs.getString("name"));
                        return u;
                    }},id);
                return user;
            }
            //查(查詢表中總共有幾條記錄)
            @Override
            public int getTotalCount() {
                String sql="select count(*) from t_user";
                Integer count = jt.queryForObject(sql,Integer.class);
                return count;
            }
            //查(查詢獲取表中的所以記錄物件,獲取的是集合物件)
            @Override
            public List<User> getAll() {
                String sql="select * from t_user";
                List<User> userList = jt.query(sql, new RowMapper<User>(){
                    @Override
                    public User mapRow(ResultSet rs, int arg1) throws SQLException {
                        User user=new User();
                        user.setId(rs.getInt("id"));
                        user.setName(rs.getString("name"));
                        return user;
                    }});
                return userList;
            }
(4)將資料庫資訊配置到屬性檔案中
            <1>在src下建立一個配置檔案,如 jdbc.properties
                     內容如下:
                        jdbc.driverClass=com.mysql.jdbc.Driver
                    jdbc.url=jdbc:mysql:///spring_crm
                    jdbc.username=root
                    jdbc.password=123
            <2>在applicationContext主配置檔案中
                    方式一:
                    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                    <property name="location" value="classpath:jdbc.properties"/>
                    </bean>
                    方式二:
                    <context:property-placeholder location="classpath:jdbc.properties"/>

Spring事務管理

1事務回顧

        <1>什麼是事務:
                事務邏輯上的一組操作,組成這組操作的各個邏輯單元,要麼一起成功,要麼一起失敗.
        <2>事務特性:
                原子性 :強調事務的不可分割.
                一致性 :事務的執行的前後資料的完整性保持一致.
                隔離性 :一個事務執行的過程中,不應該受到其他事務的干擾
                永續性 :事務一旦結束,資料就持久到資料庫
        <3>如果不考慮隔離性引發安全性問題:
                髒讀  :一個事務讀到了另一個事務的未提交的資料
                不可重複讀 :一個事務讀到了另一個事務已經提交的 update 的資料導致多次查詢結果不一致.
                虛幻讀 :一個事務讀到了另一個事務已經提交的 insert 的資料導致多次查詢結果不一致.
        <4>解決讀問題: 設定事務隔離級別
                未提交讀  :髒讀,不可重複讀,虛讀都有可能發生
                已提交讀  :避免髒讀。但是不可重複讀和虛讀有可能發生
                可重複讀  :避免髒讀和不可重複讀.但是虛讀有可能發生.
                序列化的  :避免以上所有讀問題.
        <5>
                Mysql 預設:可重複讀
                Oracle 預設:讀已提交          

2 相關的API介面

(1) 平臺事務管理器 PlatformTransactionManager
    <1> org.springframework.jdbc.datasource.DataSourceTransactionManager  
          SpringJDBC  或 iBatis 使用
    <2> org.springframework.orm.hibernate3.HibernateTransactionManager
          Hibernate 進行持久化資料時使用
(2)事務定義資訊介面 TransactionDefinition 
     事務定義資訊內容包括:
        * 隔離級別
        * 傳播行為 
                    事務的傳播的格式為:PROPAGION_XXX  
                    & 保證同一個事務中
                            PROPAGATION_REQUIRED 支援當前事務,如果不存在 就新建一個(預設)
                            PROPAGATION_SUPPORTS 支援當前事務,如果不存在,就不使用事務
                            PROPAGATION_MANDATORY  支援當前事務,如果不存在,丟擲異常
                    & 保證不在同一個事務中
                            PROPAGATION_REQUIRES_NEW  如果有事務存在,掛起當前事務,建立一個新的事務
                            PROPAGATION_NOT_SUPPORTED  以非事務方式執行,如果有事務存在,掛起當前事務
                            PROPAGATION_NEVER 以非事務方式執行,如果有事務存在,丟擲異常
                            PROPAGATION_NESTED 如果當前事務存在,則巢狀事務執行
        * 超時資訊
        * 是否只讀
(3) 事務狀態介面 TransactionStatus,記錄事務的狀態

2 Spring事務管理過程簡述

平臺事務管理器(PlatformTransactionManager)  
根據  事務定義的資訊(TransactionDefinition ) 
將事務管理過程中的狀態記錄到  TransactionStatus裡面

3 Spring事務管理分類

(1)傳統的事務管理方式:程式設計式事務方式(手動編寫程式碼完成事務的管理)
     <1> Jdbc相關程式碼示例:
            (Connection) conn.setAutoCommit(false);  //設定手動管理事務
    <2>Hibernate相關程式碼示例:
            Session.beginTransaction();
    <3>特點分析:
        優點:細粒度的事務控制,可以對指定方法,或指定方法的某幾行進行事務控制。
        缺點:雖靈活,但繁瑣,每次要開啟 ,提交,回滾,且要釋放資源,否則耗記憶體。
(2)Spring提供對事務的管理,這就叫做宣告式事務管理。
    <1>宣告式事務管理特點:
            粗粒度的事務控制,只能給整個方法應用事務,不可以對方法的某幾行應用事務。
            其核心是基於 AOP的。
    <2>Spring宣告式事務管理器分類:
        Jdbc技術:DataSourceTransactionManager
        Hibernate技術:HibernateTransactionManager
    <3>xml宣告式事務管理配置如下:
        《1》<!--配置spring的事務核心管理器,封裝了所有事務操作,依賴於連線池 -->
        <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager ">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        《2》<!--配置spring事務模板物件,用於service層程式碼API呼叫,依賴於spring的事務核心管理器  -->
        <bean name="transcationTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="transactionManager"></property>
        </bean>
        《3》將spring事務模板物件 依賴到service層中
        <bean name="accountService" class="cn.sss.service.AccountServiceImp">
            <property name="ad" ref="accountDao"></property>
            <property name="tt" ref="transcationTemplate"></property>
        </bean>
        《4》<!-- 配置事務通知 ,依賴spring事務核心管理器-->
        <tx:advice transaction-manager="transactionManager" id="txAdvice">
            <tx:attributes>
                <!--以方法為單位,指定方法應用什麼事務屬性  
                        name:要進行事務管理 的方法名
                        isolation:設定事務的隔離級別
                        propagation:事務的傳播行為
                        read-only:只讀
                  -->
                <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <!--下面為企業中的事務管理 的方法配置(使用萬用字元 *)  -->
                <tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
                <tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
                <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
            </tx:attributes>
        </tx:advice>
        《5》<!--配置織入(把事務通知織入到目標物件中)  -->
                <aop:config>
                    <!--配置切點(需增強的方法)  -->
                    <aop:pointcut expression="execution(* cn.itheima.service.*ServiceImp.*(..))" id="txPc"/>
                    <!-- 配置切面(切點+通知)
                        advice-ref:通知名稱
                        pointcut-ref:切點名稱
                     -->
                    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/>
                </aop:config>

<4>註解 實現spring宣告式事務管理
    * 主配置檔案為:
        <!--配置spring的事務核心管理器,封裝了所有事務操作,依賴於連線池 -->
        <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager ">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--配置spring事務模板物件,依賴於spring的事務核心管理器  -->
        <bean name="transcationTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="transactionManager"></property>
        </bean>
        <!--開啟使用註解管理aop事務  -->
        <tx:annotation-driven/>
    * 業務service層:
        & 在類上方使用註解  注入aop事務管理的配置,作用於整個類中所有的方法
        @Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
        public class AccountServiceImp implements AccountService {}
        & 在方法名前使用註解配置aop事務(作用於此方法,許可權大於在類上寫入的註解)
        @Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
        public void transfer(Integer from, Integer to, Double money) {}