JdbcTemplate
JdbcTemplate是 spring 框架中提供的一個對象,它的作用和QueryRunning一樣,是對原始 Jdbc API 對象的簡單封裝。 spring 框架提供了很多正對不同數據庫類型的模板類。
操作關係型數據:
JdbcTemplate
HibernateTemplate
操作 nosql 數據庫
RedisTemplate
操作消息隊列
JmsTemplate
使用JdbcTemplate的兩種方式
方法一 在dao中定義JdbcTemplate
XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--配置密碼、連接等-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test02"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!-- 配置一個數據庫的操作模板: JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
DaoImpl代碼
@Repository
public class AccountDaoImpl2 implements IAccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Account findAccountById(Integer accountId) {
List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
public Account findAccountByName(String accountName) {
List<Account> accounts = jdbcTemplate.query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw new RuntimeException("結果集不唯一");
}
return accounts.get(0);
}
@Override
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
分析
在正常的開發中,當 dao 有很多時,每個 dao 都有以下重複性的代碼:
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
基於解決這個問題的出發點,有了第二個JdbcTemplate的使用方式
方法二 讓 dao 繼承 JdbcDaoSupport
示例代碼如下:
/**
* 賬戶的持久層實現類
*/
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
@Override
public Account findAccountById(Integer accountId) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
public Account findAccountByName(String accountName) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw new RuntimeException("結果集不唯一");
}
return accounts.get(0);
}
@Override
public void updateAccount(Account account) {
super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
Spring 中的事務控制
事務控制是爲了保證我們在與數據庫進行交互的時候能保持一致性。
第一: JavaEE 體系進行分層開發,事務處理位於業務層, Spring 提供了分層設計業務層的事務處理解決方
案。
第二: spring 框架爲我們提供了一組事務控制的接口。這組接口是在spring-tx-5.0.2.RELEASE.jar 中。
第三: spring 的事務控制都是基於 AOP 的,它既可以使用編程的方式實現,也可以使用配置的方式實現。 我們學習的重點是使用配置的方式實現。
Spring 中事務控制的 API 介紹
PlatformTransactionManager
此接口是 spring 的事務管理器,它裏面提供了我們常用的操作事務的方法,以下是3個主要的方法。
- 獲取事務的狀態信息
- TransactionStatus getTransaction(TransactionDefinition definition)
- 提交事務
- void commit(TransactionStatus status)
- 回滾事務
- void rollback(TransactionStatus status)
TransactionDefinition
- 獲取事務對象名稱
- String getName()
- 獲取事務隔離級別
- int getlsolationLevel()
- 獲取事務傳播行爲
- int getPropagationBehavior()
- 獲取事務超時時間
- int getTimeout()
- 獲取事務是否只讀
- boolean isReadOnly()
事務的傳播行爲
- REQUIRED:如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。一般的選擇(默認值)
- SUPPORTS:支持當前事務,如果當前沒有事務,就以非事務方式執行(沒有事務)
- MANDATORY:使用當前的事務,如果當前沒有事務,就拋出異常
- REQUERS_NEW:新建事務,如果當前在事務中,把當前事務掛起。
- NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起
- NEVER:以非事務方式運行,如果當前存在事務,拋出異常
- NESTED:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行 REQUIRED 類似的操作。
Spring對事務的控制方式可以有兩種,一種是基於XML的聲明事務的控制方式,另一種是基於註解的聲明事務的控制方式。
是否只讀事務
建議查詢時設置爲只讀。
基於XML的聲明事務的控制方式
bean.xml
1、 配置事務管理器
2、 配置事務的通知
3、 配置AOP
4、配置切入店方法
5、建立切入點和事務的表達式
<?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">
<!--配置bean對象-->
<bean id="accountService" class="com.gzgs.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="com.gzgs.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置數據源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test02"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!-- spring中基於XML的聲明式事務控制配置步驟
1、配置事務管理器
2、配置事務的通知
此時我們需要導入事務的約束 tx名稱空間和約束,同時也需要aop的
使用tx:advice標籤配置事務通知
屬性:
id:給事務通知起一個唯一標識
transaction-manager:給事務通知提供一個事務管理器引用
3、配置AOP中的通用切入點表達式
4、建立事務通知和切入點表達式的對應關係
5、配置事務的屬性
是在事務的通知tx:advice標籤的內部
-->
<!--配置事務管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事務的通知-->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"></tx:method>
</tx:attributes>
</tx:advice>
<!--配置AOP-->
<aop:config>
<!--配置切入店方法-->
<aop:pointcut id="pt1" expression="execution(* com.gzgs.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入點和事務的表達式-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1">
</aop:advisor>
</aop:config>
</beans>
基於註解的聲明事務的控制方式
AccountDaoImpl代碼
package com.gzgs.dao.impl;
import com.gzgs.bean.Account;
import com.gzgs.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public Account findAccountById(int accountId) {
List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
public Account findAccountByName(String accountName) {
List<Account> accounts = jdbcTemplate.query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw new RuntimeException("結果集不唯一");
}
return accounts.get(0);
}
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
AccountServiceImpl代碼
package com.gzgs.service.impl;
import com.gzgs.bean.Account;
import com.gzgs.dao.AccountDao;
import com.gzgs.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* 賬戶的業務層實現類
*
* 事務控制應該都是在業務層
*/
@Service("accountService")
//只讀型事務的配置
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public Account findAccountById(int accountId) {
return accountDao.findAccountById(accountId);
}
//需要的是讀寫型事務配置
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
public void transfer(String sourceName, String targetName, double money) {
//查詢轉出賬戶
Account source = accountDao.findAccountByName(sourceName);
//查詢轉入賬戶
Account target=accountDao.findAccountByName(targetName);
//轉出賬戶扣錢
source.setMoney(source.getMoney()-money);
//轉入賬戶加錢
target.setMoney(target.getMoney()+money);
//更新轉出賬戶
accountDao.updateAccount(source);
// int a=2/0;
//更新轉入賬戶
accountDao.updateAccount(target);
}
}
bean.xml代碼
<?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"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置掃描的路徑-->
<context:component-scan base-package="com.gzgs"></context:component-scan>
<!--開啓Spring對註解事務的支持-->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
<!--配置數據源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test02"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!-- 配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事務管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
基於純註解的聲明事務的控制方式
定義配置類
SpringConfigruation
package config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* spring的配置類,相當於bean.xml
*/
@Configuration
@ComponentScan("com.gzgs")
@PropertySource("jdbcConfig.properties")
@Import({jdbcConfig.class,TransactionConfig.class})
@EnableTransactionManagement//開啓Spring對註解事務支持
public class SpringConfiguration {
}
jdbcConfig
package config;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
public class jdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 返回用於進行數據查詢的JdbcTemplate對象
* @param dataSource
* @return
*/
@Bean(name = "jdbcTemplate")
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
/**
*
* 創建數據源
* @return
*/
@Bean(name = "dataSource")
public DataSource createDataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
}
TransactionConfig
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
import javax.sql.DataSource;
/**
* 和事務相關的配置類
*/
public class TransactionConfig {
/**
* 用於創建TransactionManager
* @param dataSource
* @return
*/
@Bean(name = "txManager")
public PlatformTransactionManager createTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
本博客純屬個人學習筆記,學習資源來自黑馬訓練營,如有錯誤,感激指正