Spring的持久層封裝

傳統JDBC技術

下面的代碼只是一個使用JDBC連接的示例,實際應用中不會這樣用,一是代碼繁瑣,一是效率低。而Spring在持久層提供了更好的支持,對JDBC進行了良好的封裝。

public class HelloWorld {
	Connection conn = null;
	Statement stml = null;
	{
		try {
			//獲取數據連接
			Class.forName(com.microsoft.jdbc.sqlserver.SQLServerDriver);
			conn.DriverManager.getConnection(jdbc:microsoft:sqlserver:\\localhost:1433\stdb,admin,admin);
			//開始啓動事務
			conn.setAutoCommit(false);
			stml = conn.createStatement();
			//執行相應操作
			stml.executeUpdate("insert into hello values(1,'gf','HelloWorld')");
			//執行成功則提交事務
			conn.commit();
		} catch (SQLException e) {
			if (conn != null) {
				try {
					//執行不成功,則回滾
					conn.rollback();
				} catch (SQLException ex) {
					System.out.println("數據連接有異常" + ex);
				}
			}
		} finally {
			//假如stmt不爲空,則關閉 stmt
			if (stml != null) {
				try {
					stml.close();
				} catch (SQLException ex) {
					System.out.println("執行操作有異常" + ex);
				}
			} 
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException ex) {
					System.out.println("數據連接有異常" + ex);
				}
			}
		}
	}
}

通過XML實現DataSource(數據源)注入

Spring提供了3種XML實現數據源注入的方式:使用Spring自帶的DriverManagerDataSource、使用DBCP連接池、使用Tomcat提供的JNDI。

(1)使用Spring自帶的DriverManagerDataSource

使用DriverManagerDataSource在效率上和直接使用JDBC沒有多大區別。配置文檔和對於的java程序示例如下:

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
	</bean>
</beans>
public class HelloDAO {
	private DataSource dataSource;
	private PlatformTransactionManager transactionManager;
	//通過依賴注入來完成管理
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	//使用TransactionTemplate對create()方法進行事務管理
	public int create(String msg) {
		TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
		//調用TransactionTemplate的execute()方法,並覆寫TransactionCallback類的doInTransaction()方法,在該方法裏進行對數據庫的新增操作
		Object result = transactionTemplate.execute(
			new TransactionCallback() {
			@Override
			public Object doInTransaction(TransactionStatus status) {
				JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
				Object resultObject = jdbcTemplate.update("INSERT INTO hello VALUES(1,'gf','HelloWorld')");
				return resultObject;
			}
		});	
	}
}

(2)使用DBCP連接池

Spring提供了DBCP連接池的支持,可以直接在配置文檔中配置DBCP數據庫連接池。

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
	</bean>
</beans>

(3)使用Tomcat提供的JNDI

與使用DBCP連接池相比,使用Spring來進行Web開發,更多的使用Web容器提供的數據庫連接池功能。如使用Romcat容器,及Tomcat提供的JNDI的配置。

首先在Tomcat的server.xml中添加以下代碼:

<Context path="/myApp" reloadable="true" docBase="D:\eclipse\workspace\myApp" workDir="D:\eclipse\workspace\myApp\work">
	<Resource name="jdbc/opendb" auth="Container" 
		type="javax.sql.DataSource" 
		factory="org.apache.tomcat.dbcp.BasicDataSourceFactory" 
		driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver" 
		url="jdbc:microsoft:sqlserver://localhost:1433/stdb"
		<!--設定用戶名-->
		name="admin"
		<!--設定密碼-->
		msg="admin"
		<!--設定最大連接數-->
		maxActive="10000"
		<!--設定最大空閒時間-->
		maxIdle="10000"
		<!--設定最大等待時間-->
		maxWait="10000"
		removeAbandoned="true"
		removeAbandonedTimeout="10"
		logAbandoned="true"
	/>
</Context>	

Spring配置如下:

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName">
			<value>jndi/opendb</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
	</bean>
</beans>

使用JdbcTemplate訪問數據

(1)Template模式簡介

Template模式:就是在父類中定義一個操作中算法的骨架或者說操作順序,而將一些步驟的具體實現延遲到子類中。這個模式可能是最簡單的模式了。

(1)父類骨架代碼

package com.gc.action;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public abstract class Transaction{
	//事務處理的骨架代碼,指明事務處理的操作順序
	public Object execute() throws TransactionException {
		this.transactionManager.getTransaction(this);
		Object result = null;
		try {
			
		} catch (Error err) {
			// Transactional code throw error -> rollback
			this.transactionManager.rollback(this);
			throw err;
		}
		this.transactionManager.commit(this);
		return result;
	}
	//負責傳入具體的事務
	public abstract Object doInTransaction();
}

(2)子類具體要進行事務處理的代碼

public class SubTransaction extends Transaction {
    //負責傳入具體的事務
    public Object doInTransaction() {
        //具體對數據庫進行增刪改的代碼
    }
}

(2)事務處理中的TransactionTemplate的實現方式

TransactionTemplate事務處理代碼:

public class TransactionTemplate extends DefaultTransactionDefinition implements InitializingBean {
	private PlatformTransactionManager transactionManager = null;
	//通過依賴注入
	public TransactionTemplate(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	public PlatformTransactionManager getTransactionManager() {
		return transactionManager;
	}
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	//執行完畢後調用
	public void afterPropertiesSet() {
		if (this.transactionManager == null) {
			throw new IllegalAnnotationException("transactionManager is required");
		}
	}
	//進行事務處理的骨架,指明瞭事務處理的順序
	public Object execute(TransactionCallback action) throws TransactionException {
		TransactionStatus status = this.transactionManager.getTransaction(this);
		Object result = null;
		try {
			//執行具體的方法
			result = action.doInTransaction(status);
		} catch (RuntimeException ex) {
			// Transactional code threw application exception -> roolback
			rollbackOnException(status,ex);
			throw ex;
		} catch (Error err) {
			// Transactional code threw error -> roolback
			rollbackOnException(status,err);
			throw err;
		}
		this.transactionManager.commit(status);
		return result;
	}
	//如果有異常就rollback
	private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException{
		try {
			this.transactionManager.rollback(status);
		} catch (RuntimeException ex2) {
			throw ex2;
		} catch (Error err) {
			throw err;
		}		
	}
}

這裏的TransactionTemplate沒有抽象類,在它的execute()方法裏定義事務處理的骨架代碼。但是execute()方法裏的TransactionCallback參數卻是個接口,在這個接口中定義了doInTransaction()方法。

public interface TransactionCallback {
    Object doInTransaction(TransactionStatus status);
}

只要實現這個接口,並在doInTransaction()方法裏編寫具體要進行事務處理的代碼就可以了。

public class HelloDAO {
	private DataSource dataSource;
	private PlatformTransactionManager transactionManager;
	//通過依賴注入來完成管理
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	//使用TransactionTemplate對create()方法進行事務管理
	public int create(String msg) {
		TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
		//調用TransactionTemplate的execute()方法,並覆寫TransactionCallback類的doInTransaction()方法,在該方法裏進行對數據庫的新增操作
		Object result = transactionTemplate.execute(
			new TransactionCallback() {
			@Override
			public Object doInTransaction(TransactionStatus status) {
				JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
				Object resultObject = jdbcTemplate.update("INSERT INTO hello VALUES(1,'gf','HelloWorld')");
				return resultObject;
			}
		});	
	}
}

(3)JdbcTemplate的實現方式

JdbaTemplate封裝了傳統JDBC的功能也實現了Template模式。但與TransactionTemplate有些不同。

import jdk.nashorn.internal.runtime.Context.ThrowErrorManager;

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations{
	......
	//使用回調方法
	public Object execute(ConnectionCallback action) throws DataAccessException {
		Connection con = DataSourceUtils.getConnection(getDataSource());
		try {
			Connection conToUse = con;
			if (this.nativeJdbcExtractor != null) {
				//Extract native JDBC Connection, castable t OracleConnection or the like.
				conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
			}
			else {
				//創建一個連接代理
				conToUse = createConnectionProxy(con);
			}
			return action.doInConnection(conToUse);
		} catch (SQLException ex) {
			// 釋放連接
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
		} finally {
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}
	//使用回調方法
	public Object execute(StatementCallback action) throws DataAccessException {
		Connection con = DataSourceUtils.getConnection(getDataSource());
		Statement stml = null;
		try {
			Connection conToUse = con;
			if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
				//Extract native JDBC Connection, castable t OracleConnection or the like.
				conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
			}
			//創建Statement
			stml = conToUse.createStatement();
			applyStatementSetting(stml);
			Statement stmlToUse = stml;
			if (this.nativeJdbcExtractor != null) {
				stmlToUse = this.nativeJdbcExtractor.getNativeStatement(stml);
			}
			//初始化Statement
			Object result = action.doInStatement(stmlToUse);
			SQLWarning warning = stml.getWarnings();
			throwExceptionOnWarningIfNotIgnoringWarnings(warning);
			return result;
		} catch (SQLException ex) {
			// 釋放連接
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
		} finally {
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}
	......
}

從上面JdbaTemplate的部分代碼可以看出,JdbaTemplate與TransactionTemplate類似,都有execute()方法,並且execute()方法是一個接口。但是JdbaTemplate不需要在代碼中使用回調方法,可以只是把SQL語句傳入,直接執行。當然,也可以使用回調方法。

JdbaTemplate的使用:

(1)首先編寫配置文檔,然後通過程序使用JdbaTemplate,並於事務處理結合在一起。

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
	</bean>
</beans>
public class HelloDAO {
	private DataSource dataSource;
	private PlatformTransactionManager transactionManager;
	//通過依賴注入來完成管理
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	//使用JdbcTemplate
	public void create(String msg) {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();//默認事務定義
		TransactionStatus status = transactionManager.getTransaction(def);//聲明事務開始
		try {
			//使用JdbcTemplate往數據庫裏新增數據
			JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
			jdbcTemplate.update("INSERT INTO hello VALUES(1,'gf','HelloWorld')");
		} catch (DataAccessException ex) {
			// 也可以執行status.setRollbackOnly();
			transactionManager.rollback(status);
			throw ex;
		} finally {
			transactionManager.commit(status);
		}
	}
}

把配置文檔中定義的dataSource通過JdbcTemplate的構造方法進行注入,然後直接執行JdbcTemplate的update()方法即可實現對數據庫的操作。需要兩行代碼實現對數據庫的操作。

(2)還可以把配置文檔中定義的dataSource通過JdbcTemplate的構造方法進行注入也省略掉,直接在配置文檔中配置,並使JdbcTemplate依賴於dataSource。這樣只需要一行代碼就可以實現對數據庫的操作。

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--設定jdbcTemplate-->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<!--依賴注入jdbcTemplate-->
		<property name="jdbcTemplate">
			<ref bean="jdbcTemplate"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
	</bean>
</beans>
public class HelloDAO {
	private JdbcTemplate jdbcTemplate;
	private PlatformTransactionManager transactionManager;
	//通過依賴注入來完成管理
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	//使用JdbcTemplate
	public void create(String msg) {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();//默認事務定義
		TransactionStatus status = transactionManager.getTransaction(def);//聲明事務開始
		try {
			//使用JdbcTemplate往數據庫裏新增數據
			jdbcTemplate.update("INSERT INTO hello VALUES(1,'gf','HelloWorld')");
		} catch (DataAccessException ex) {
			// 也可以執行status.setRollbackOnly();
			transactionManager.rollback(status);
			throw ex;
		} finally {
			transactionManager.commit(status);
		}
	}
}

(3)當然,既然構造方法的數據注入可以通過修改配置文件實現,那麼要執行的SQL語句當然也可以通過配置文檔進行配置,這樣如果需要修改SQL語句,就不需要改變代碼,只需要修改配置文檔就可以了。

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--設定jdbcTemplate-->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<!--依賴注入jdbcTemplate-->
		<property name="jdbcTemplate">
			<ref bean="jdbcTemplate"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
		<property name="sql">
			<value>INSERT INTO hello VALUES(1,'gf','HelloWorld')</value>
		</property>
	</bean>
</beans>
public class HelloDAO {
	private JdbcTemplate jdbcTemplate;
	private PlatformTransactionManager transactionManager;
	private String sql;
	//通過依賴注入來完成管理
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}	
	public void setSql(String sql) {
		this.sql = sql;
	}
	//使用JdbcTemplate
	public void create(String msg) {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();//默認事務定義
		TransactionStatus status = transactionManager.getTransaction(def);//聲明事務開始
		try {
			//使用JdbcTemplate往數據庫裏新增數據
			jdbcTemplate.update(this.sql);
		} catch (DataAccessException ex) {
			// 也可以執行status.setRollbackOnly();
			transactionManager.rollback(status);
			throw ex;
		} finally {
			transactionManager.commit(status);
		}
	}
}

以上三種方法,代碼量逐漸減少,並且都通過依賴注入實現。

(4)使用JdbaTemplate查詢數據庫

JdbaTemplate提供了很多用來查詢數據庫的方法:queryForMap()、queryForLong()、queryForInt()、queryForList()等。

List rows = jdbcTemplate.queryForList("select * from hello");
Iterator it = rows.iterator();
//通過Iterator獲取list的值
while(it.hasNext()){
    Map map = (Map)it.next();
    String id = map.get("id");
    String name = map.get("name");
    String mag = map.get("mag");
}


int count = jdbcTemplate.queryForInt("select count(*) from hello");

(5)使用JdbaTemplate更改數據庫

JdbcTemplate中的update()方法使進行數據庫更愛的常用方式。

jdbcTemplate.update("insert into hello values(1,'gf','HelloWorld')");

jdbcTemplate.update("insert into hello values(?,?,?,)",new Object[]{1,'gf','HelloWorld'});

jdbcTemplate.update("insert into hello values(?,?,?,)",
                        new PreparedStatementSetter(){
                            public void setValues(PreparedStatement ps) throws SQLException {
                                ps.setInt(1,1);
                                ps.setInt(2,'gf');
                                ps.setInt(3,'HelloWorld');
                            }
                        }
                    );

jdbcTemplate.update("update hello set name='gf',msg='HelloWorld' where id=1");

jdbcTemplate.update("update hello set name=?,msg=? where id=?",new Object[]{'gf','HelloWorld',1});

使用ORM工具訪問數據

(1)ORM簡述

ORM(Object-Relational Mapping):對象關係映射。

因爲開發人員使用的技術是面向對象技術,而使用的數據庫卻是關係型數據庫。使用ORM,通過在對象和關係型之間建立起一座橋樑。Hibernate、iBatis就是這樣的ORM工具。

ORM包括以下四個部分:

  • 一個對持久類對象進行CRUD操作的API。
  • 一個語言或API用來規定與類和類屬性相關的查詢。
  • 一個規定mapping metadata的工具。
  • 一種技術可以讓ORM的實現同事務對象一起進行dirty checking,lazy association fetching以及其他的優化操作。

ORM模型的簡單性簡化了數據庫查詢過程。使用ORM查詢工具,用戶可以訪問期望數據,而不必理解數據庫的底層結構。

(2)使用Hibernate

Hibernate主要應用在持久層方面。

Spring與Hibernate結合在一起:

  • 加入Hibernate後的Spring的配置文檔
  • Hibernate的配置文件Hello.hbm.xml
  • 存放數據的類Hello
  • HelloDAO的編寫
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--使用Hibernate的sessionFactory-->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref local="dataSource"/>
		</property>
		<property name="mappingResources">
			<list>
				<value>com/gc/gction/Hello.hbm.xml</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<!--設定方言-->
				<prop key="hibernate.dialect">
					net.sf.hibernate.dialect.SQLServerDialect
				</prop>
				<!--是否顯示sql-->
				<prop key="hibernate.show_sql">
					true
				</prop>
			</props>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="sessionFactory">
			<ref bean="sessionFactory"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<!--依賴注入jdbcTemplate-->
		<property name="sessionFactory">
			<ref bean="sessionFactory"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
	</bean>
</beans>
<!--Hello.hbm.xml-->
<hibernate-mapping>
<class name="com.gc.action.Hello" table="hello" dynamic-update="false" dynamic-insert="false">
<id name="id" column="id" type="java.lang.Integer"/>
<property name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
<!--欄位名稱爲msg-->
column="msg"
<!--字段長度爲50-->
length="50"/>
<property name="msg"
type="java.lang.String"
update="true"
insert="true"
access="property"
<!--欄位名稱爲name-->
column="name"
<!--字段長度爲50-->
length="50"/>
</class>
</hibernate-mapping>
/**
* @hibernate.class table="hello"
*/
public class Hello {
    public Integer id;
    public String name;
    public String msg;
    /**
    * @hibernate.id
    * column="id"
    * type="java.lang.Integer"
    */
    public Integer getID() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    /**
    * @hibernate.property column="msg" length="50"
    */
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    /**
    * @hibernate.property column="name" length="50"
    */
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

在HelloDAO中使用SessionFactory,並和事務處理結合。

public class HelloDAO {
	private SessionFactory sessionFactory;
	private PlatformTransactionManager transactionManager;
	private String sql;
	//通過依賴注入來完成管理
	public void setSessionFactory(DataSource sessionFactory) {
		this.sessionFactory = sessionFactory;
	}	
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}	
	//使用HibernateTemplate
	public void create(String msg) {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();//默認事務定義
		TransactionStatus status = transactionManager.getTransaction(def);//聲明事務開始
		try {
			HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
			//定義一個Hello
			Hello hello = new Hello();
			hello.setId(1);
			hello.setName("gf");
			hello.setMsg("HelloWorld");
			//保存或更新hello
			hibernateTemplate.saveOrUpdate(hello);
		} catch (DataAccessException ex) {
			// 也可以執行status.setRollbackOnly();
			transactionManager.rollback(status);
			throw ex;
		} finally {
			transactionManager.commit(status);
		}
	}
}

(3)使用iBatis

iBatis主要應用在持久層方面。

Spring與Hibernate結合在一起:

  • 加入iBatis後的Spring的配置文檔
  • iBatis的配置文件sqlMapConfig.xml
  • 存放數據的類Hello
  • HelloDAO的編寫
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--設定dataSource-->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<!--使用SQL Server數據集-->
		<property name="driverClassName">
			<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
		</property>
		<!--設定URL-->
		<property name="url">
			<value>jdbc:microsoft:sqlserver://localhost:1433/stdb</value>
		</property>
		<!--設定用戶名-->
		<property name="name">
			<value>admin</value>
		</property>
		<!--設定密碼-->
		<property name="msg">
			<value>admin</value>
		</property>
	</bean>
	<!--使用iBatis-->
	<bean id="sqlMap" class="org.springframework.orm.iBatis.SqlMapClientFactoryBean">
		<property name="configLocation">
			<value>WEB-INF/sqlMapConfig.xml</value>
		</property>
	</bean>
	<!--設定transactionManager-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
	</bean>
	<!--示例中的一個DAO-->
	<bean id="helloDAO" class="com.gc.action.HelloDAO">
		<!--依賴注入jdbcTemplate-->
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		<property name="transactionManager">
			<ref bean="transactionManager"/>
		</property>
		<property name="sqlMap">
			<ref bean="sqlMap"/>
		</property>
	</bean>
</beans>
<!--sqlMapConfig.xml-->
<sqlMapConfig>
    <sqlMap resource="com/gc/action/Hello.xml"/>
</sqlMapConfig>
<!--Hello.xml-->
<sqlMap namespace="Hello">
    <typeAlias alias="hello" type="com.gc.action.Hello" />
    <insert id="insertHello" parameterClass="hello">
        insert into hello (id,name,msg) values(#id#,#name#,#msg#)
    </insert>
</sqlMap>
public class Hello {
    public Integer id;
    public String name;
    public String msg;
   
    public Integer getID() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
   
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//HelloDAO.java
public class HelloDAO extends SqlMapClientDaoSupport {
	private PlatformTransactionManager transactionManager;
	//通過依賴注入來完成管理
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}	
	//使用getSqlMapClientTemplate
	public void create(String msg) {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();//默認事務定義
		TransactionStatus status = transactionManager.getTransaction(def);//聲明事務開始
		try {
			//定義一個Hello
			Hello hello = new Hello();
			hello.setId(1);
			hello.setName("gf");
			hello.setMsg("HelloWorld");
			//保存或更新hello
			getSqlMapClientTemplate().update("insertHello",hello);
		} catch (DataAccessException ex) {
			// 也可以執行status.setRollbackOnly();
			transactionManager.rollback(status);
			throw ex;
		} finally {
			transactionManager.commit(status);
		}
	}
}

 

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