Spring2學習筆記(2)-使用數據庫

1 使用數據庫

1.1 配置數據源

1.1.1 JNDI 數據源

  < bean id = "dataSource"

      class = "org.springframework.jndi.JndiObjectFactoryBean" scope = "singleton" >

    < property name = "jndiName" value = "/jdbc/RantzDatasource" />

    < property name = "resourceRef" value = "true" />

  </ bean >

resourceRef :當爲 true 的時候, jndiName 會被添加 java:comp/env/

Spring2.0 裏使用 jee 命名空間裏的配置

  < jee:jndi-lookup id = "dataSource"

    jndi-name = "/jdbc/RantzDatasource"

    resource-ref = "true" />    

 

1.1.2   基於 JDBC 驅動的數據源

  < bean id = "dataSource"

      class = "org.springframework.jdbc.datasource.DriverManagerDataSource" >

< property name = "driverClassName"

value = " oracle.jdbc.driver.OracleDriver " />

< property name = "url"

value = " jdbc:oracle:thin:@192.168.1.1:1521:test " />

    < property name = "username" value = "zrl" />

    < property name = "password" value = "" />

  </ bean >

1.1.3   使用數據源連接池

類似 JDBC 驅動,使用 org.apache.commons.dbcp.BasicDataSource 類驅動

 

1.2    使用 JDBC

1.2.1   使用 JDBC 模板

編寫基於 JDBC DAO 涉及配置 JDBC 模板 Bean 、把它裝配到 DAO 類、然後使用這個模板訪問數據庫,這個過程要配置 3 Bean :一個數據源、一個模板、一個 DAO

JdbcTemplate :最基本的 JDBC 模板,利用 JDBC 和簡單的索引參數對數據庫的簡單訪問

NamedParameterJdbcTemplate :能夠在執行查詢時把值綁定到 SQL 裏的命名參數,而不是使用索引參數

SimpleJdbcTemplate :選用 java5 的特性,來簡化 JDBC 模板的使用

 

1.2.1.1             JdbcTemplate

1)        XML 配置

  < bean id = "jdbcTemplate"

    class = "org.springframework.jdbc.core.JdbcTemplate" >

    < property name = "dataSource" ref = "dataSource" />

  </ bean >

2)        JdbcTemplate 裝配到 DAO

public class JdbcRantDao implements RantDao {

...

   private JdbcTemplate jdbcTemplate ;

   public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

       this . jdbcTemplate =jdbcTemplate;

   }

}

3)        設置 JdbcRantDao jdbcTemplate 屬性

  < bean id = "rantDao" class = "com.roadrantz.dao.jdbc.JdbcRantDao" >

    < property name = "jdbcTemplate" ref = "jdbcTemplate" />

  </ bean >

 

4)        使用保存

   private static final String MOTORIST_INSERT = "insert into motorist (id, email, password, firstName, lastName) "

                     + "values (null, ?,?,?,?)" ;

   public void saveMotorist(Motorist motorist) {

      jdbcTemplate .update(

                        MOTORIST_INSERT ,

                        new Object[] { motorist.getEmail(),

                              motorist.getPassword(), motorist.getFirstName(),

                               motorist.getLastName() });

   }

5)        使用查詢

   private static final String MOTORIST_SELECT = "select id, email, password, firstName, lastName from motorist" ;

   private static final String MOTORIST_BY_ID_SELECT = MOTORIST_SELECT

                     + " where id=?" ;

   public Motorist getMotoristById ( long id) {

      List matches = jdbcTemplate .query( MOTORIST_BY_ID_SELECT ,

                        new Object[] { Long.valueOf (id) }, new RowMapper() {

                           public Object mapRow(ResultSet rs, int rowNum)

                                              throws SQLException,

                                             DataAccessException {

                              Motorist motorist = new Motorist();

 

                              motorist.setId(rs.getInt(1));

                               motorist.setEmail(rs.getString(2));

                              motorist.setPassword(rs.getString(3));

                              motorist.setFirstName(rs.getString(4));

                              motorist.setLastName(rs.getString(5));

                               return motorist;

                           }

                        });

 

      return matches.size() > 0 ? (Motorist) matches.get(0) : null ;

   }

 

1.2.1.2             NamedParameterJdbcTemplate

使用方法及步驟同 jdbcTemplate

命名參數:

   private static final String MOTORIST_INSERT = "insert into motorist (id, email, password, firstName, lastName) "

                     + "values (null, :email, :password, :firstName, :lastName)" ;

使用保存

   public void saveMotorist (Motorist motorist) {

      Map<String, String> parameters = new HashMap<String, String>();

      parameters.put( "email" , motorist.getEmail());

      parameters.put( "password" , motorist.getPassword());

      parameters.put( "firstName" , motorist.getFirstName());

      parameters.put( "lastName" , motorist.getLastName());

      jdbcTemplate .update( MOTORIST_INSERT , parameters);

   }

 

1.2.1.3             SimpleJdbcTemplate

使用方法及步驟同 jdbcTemplate

查詢

   public Motorist getMotoristById ( long id) {

      List<Motorist> matches = jdbcTemplate .query(

                        MOTORIST_BY_ID_SELECT ,

                        new ParameterizedRowMapper<Motorist>() {

                            public Motorist mapRow(ResultSet rs, int rowNum)

                                             throws SQLException {

                              Motorist motorist = new Motorist();

 

                              motorist.setId(rs.getInt(1));

                               motorist.setEmail(rs.getString(2));

                              motorist.setPassword(rs.getString(3));

                              motorist.setFirstName(rs.getString(4));

                              motorist.setLastName(rs.getString(5));

                              return motorist;

                           }

                        }, id);

 

      return matches.size() > 0 ? matches.get(0) : null ;

   }

 

1.2.2   使用 Spring JDBC DAO 支持類

DAO 類繼承 JdbcDaoSupport

public class JdbcRantDao extends JdbcDaoSupport implements RantDao

只需配置 jdbcTemplate dataSource

  < bean id = "rantDao" class = "com.roadrantz.dao.jdbc.JdbcRantDao" >

    < property name = "dataSource" ref = "dataSource" />

  </ bean >

  < bean id = "rantDao" class = "com.roadrantz.dao.jdbc.JdbcRantDao" >

     < property name = "jdbcTemplate " ref = "jdbcTemplate " />

  </ bean >

使用 getJdbcTemplate().update

 

NamedParameterJdbcDaoSupport SimpleJdbcDaoSupport 的使用方法類似

 

1.3    Spring 裏集成 Hibernate

1.3.1   使用 Hibernate 模板

1)        配置 HibernateTemplate

  < bean id = "hibernateTemplate"

      class = "org .springframework .orm .hibernate3.HibernateTemplate" >

    < property name = "sessionFactory" ref = "sessionFactory" />

  </ bean >

2)        配置 sessionFactory

使用典型的 Hibernate 映射文件

   < bean id = "sessionFactory"

         class = "org .springframework .orm .hibernate3.LocalSessionFactoryBean" >

      < property name = "dataSource" ref = "dataSource" />

      < property name = "mappingResources" >

         < list >

            < value > com /roadrantz /domain/Rant.hbm .xml </ value >

            < value > com /roadrantz /domain/Motorist.hbm .xml </ value >

            < value > com /roadrantz /domain/Vehicle.hbm .xml </ value >

         </ list >

      </ property >

      < property name = "hibernateProperties" >

         < props >

            < prop key = "hibernate .dialect" > ${hibernate .dialect} </ prop >

         </ props >

      </ property >

   </ bean >  

Java5 也可以使用被註解的域對象(這裏不做說明)

3)        通過 Hibernate 模板訪問數據

public class HibernateRantDao implements RantDao {

...

   private Hibernate Template hibernate Template;

   public void setTemplate( Hibernate Template template) {

       this .hibernate Template =template;

   }

}

4)        Spring 裏配置 DAO

  < bean id = "rantDao" class = "com.roadrantz.dao.hibernate.HibernateRantDao" >

    < property name = "hibernateTemplate" ref = "hibernateTemplate" />

  </ bean >

 

5)        使用

  public Vehicle findVehicleByPlate(String state, String plateNumber) {

      List results = getHibernateTemplate()

                        .find( "from " + VEHICLE + " where state = ? and plateNumber = ?" ,

                                          new Object[] { state, plateNumber });

 

      if (results.size() > 0) {

         return (Vehicle) results.get(0);

      }

 

      return null ;

   }

 

   public Motorist getDriverById (Integer id) {

      return (Motorist) getHibernateTemplate().load(Motorist. class , id);

   }

 

 

1.3.2   建立基於 Hibernate DAO

1)        繼承 HibernateDaoSupport

public class HibernateRantDao extends HibernateDaoSupport implements RantDao

 

2)        數據訪問方法使用 getHibernateTemplate()

 

3)        修改 spring 配置的 Dao

< bean id = "rantDao" class = "com.roadrantz.dao.hibernate.HibernateRantDao" >

    < property name = "sessionFactory" ref = "sessionFactory" />

  </ bean >

 

1.3.3   使用 Hibernate3 上下文會話

HibernateTemplate 的缺點是具有一定的侵入性。使用上下文把 DAO 實現與 Spring 解耦,缺點是它們拋出 Hibernate 特有的異常

1)        定義 session

public class HibernateContextualSessionsRantDao implements RantDao {

...

   private SessionFactory sessionFactory ;

   public void setSessionFactory(SessionFactory sessionFactory) {

      this . sessionFactory = sessionFactory;

   }

}

2)        Spring 裏配置的 DAO 同上

3)        訪問

   public void saveRant (Rant rant) {

      sessionFactory .getCurrentSession() .saveOrUpdate(rant);

   }

 

1.4    緩存

Spring Modules 會提供一個代理來攔截方法並把結果保存到緩存,它並沒有提供一個實際的緩存解決方案,而是要依賴於第三方的緩存方案。這裏選擇 EHCache

1.4.1   配置緩存方案

< beans xmlns = "http://www.springframework.org/schema/beans"

       xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"

       xmlns:ehcache = "http://www.springmodules.org/schema/ehcache"

       xsi:schemaLocation = "http://www.springframework.org/schema/beans

            http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

            http://www.springmodules.org/schema/ehcache

            http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd" >

 

  < ehcache:config

     configLocation = "classpath:ehcache.xml" />

     

  < ehcache:annotations >

    < ehcache:caching id = "rantzCacheModel" cacheName = "rantzCache" />

  </ ehcache:annotations >  

</ beans >

 

EHCache.xml 文件內容

< ehcache >

  < defaultCache

      maxElementsInMemory = "500"

      eternal = "true"

      overflowToDisk = "false"

      memoryStoreEvictionPolicy = "LFU" />

  < cache name = "rantzCache"

      maxElementsInMemory = "500"

      eternal = "true"

      overflowToDisk = "false"

      memoryStoreEvictionPolicy = "LFU" />

</ ehcache >

<defaultCache> 是必須有的, <cache> 定義了另一個緩存

memoryStoreEvictionPolicy 當達到最大時的驅逐策略:最近使用 (LRU) 、先入先出 (FIFO) 、較入使用 (LFU)

1.4.2   緩存的代理 Bean

  < ehcache:proxy id = "rantDao"

      refId = "rantDaoTarget" >

    < ehcache:caching

        methodName = "getRantsForDay"

        cacheName = "rantzCache" />

    < echache:flushing

    methodName = "saveRant"

        cacheName = "rantzCache"

        when = "before" />

  </ ehcache:proxy >

< ehcache:caching> 元素聲明哪個方法要被攔截、其返回要保存到哪個緩存

< echache:flushing> 元素聲明瞭會清空緩存的方法

1.4.3   註解驅動的緩存

@Cacheable :聲明一個方法的返回值應該被緩存

@CacheFlush :聲明一個方法是清空緩存的觸發器

  @CacheFlush (modelId= "rantzCacheModel" )

  public void saveRant(Rant rant);

 

  @Cacheable (modelId= "rantzCacheModel" )

  public List<Rant> getAllRants();

 

xml 中配置

  < ehcache:annotations >

    < ehcache:caching id = "rantzCacheModel" cacheName = "rantzCache" />

    < ehcache:caching id = "rantzFlushModel" cacheName = "rantzCache" when = "before" />

  </ ehcache:annotations >

 

 

 

1.5    事務管理

ACID :原子性( Atomic )、一致性( Consistent )、隔離性( Isolated )、持久性( Durable

1.5.1   事務管理器

1.5.1.1             JDBC 事務

  < bean id = "transactionManager"

class = "org.springframework.jdbc.datasource.DataSourceTransactionManager " >

    < property name = "dataSource" ref = "dataSource" />

  </ bean >

 

1.5.1.2             Hibernate 事務

  < bean id = "transactionManager"

      class = "org.springframework.orm.hibernate3.HibernateTransactionManager " >

    < property name = "sessionFactory" ref = "sessionFactory" />

  </ bean >

 

1.5.2   Spring 中編寫事物

      

 

1.5.3   聲明式事務

public class RantServiceImpl implements RantService {

   public void addRant(Rant rant) {

      rant.setPostedDate( new Date());

      Vehicle rantVehicle = rant.getVehicle();

      Vehicle existingVehicle = rantDao .findVehicleByPlate(rantVehicle

                        .getState(), rantVehicle.getPlateNumber());

      if (existingVehicle != null ) {

         rant.setVehicle(existingVehicle);

      } else {

         rantDao .saveVehicle(rantVehicle);

      }

      rantDao .saveRant(rant);

   }

}

1.5.3.1             代理事務

  < bean id = "rantService"    class = "org.springframework.transaction.interceptor.TransactionProxyFactoryBean" >

    < property name = "target" ref = "rantServiceTarget" />   // 裝配事務目標

    < property name = "proxyInterfaces" value = "com.roadrantz.service.RantService" />        // 指定代理接口

    < property name = "transactionManager" ref = "transactionManager" /> // 裝配事務管理器

    < property name = "transactionAttributes" >      // 裝配事務規則、邊界

      < props >

        < prop key = "add*" > PROPAGATION_REQUIRED </ prop >

        < prop key = "*" > PROPAGATION_SUPPORTS,readOnly </ prop >

      </ props >

    </ property >

  </ bean >

 

PROPAGATION_REQUIRED: 表示此方法必須在一個事務中運行

PROPAGATION_SUPPORTS :表示當前方法不需要事務性上下文。

 

1.5.3.2             創建一個事務代理模板

Bean

  < bean id = "txProxyTemplate"    class = "org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract=”true” >

    < property name = "transactionManager" ref = "transactionManager" /> // 裝配事務管理器

    < property name = "transactionAttributes" >      // 裝配事務規則、邊界

      < props >

        < prop key = "add*" > PROPAGATION_REQUIRED </ prop >

        < prop key = "*" > PROPAGATION_SUPPORTS,readOnly </ prop >

      </ props >

    </ property >

  </ bean >

Bean

< bean id = "rantService" parent="txProxyTemplate" >

< property name = "target" ref = "rantServiceTarget" />  

< property name = "proxyInterfaces" value = "com.roadrantz.service.RantService" />

</ bean >

 

1.5.3.3             Spring2.0 裏聲明事務

增加 tx 名稱空間

       xmlns:tx = "http://www.springframework.org/schema/tx"

       xsi:schemaLocation = "...

          http://www.springframework.org/schema/tx

          http://www.springframework.org/schema/tx/spring-tx-2.0.xsd" >

配置通知

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

    < tx:attributes >

       < tx:method name = "add*" propagation = "REQUIRED" />

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

    </ tx:attributes >

  </ tx:advice >

通知器

  < aop:config >

< aop:advisor advice-ref = "txAdvice"

pointcut = "execution(* *..RantService.*(..))" />

  </ aop:config >

表示通知 RantService 接口的所有方法

 

1.5.3.4             註釋驅動事務

@Transactional (propagation = Propagation. SUPPORTS , readOnly = true )

public interface RantService {

  @Transactional (propagation = Propagation. REQUIRED )

  public void addRant(Rant rant);

  ...

}

只需在 XML 上加上以下配置代碼

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章