requiredType)public class JDBCTest {
private ApplicationContext applicationContext = null;
private JdbcTemplate jdbcTemplate = null;
{
applicationContext = new ClassPathXmlApplicationContext("applicationContext-jdbc.xml");
jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
}
/*
* ,
* JdbcTemplate.queryForObject(String sql, Class<T> requiredType)
*/
@Test
public void testQueryForObject2(){
String sql= "SELECT count(id) FROM employees";
Long count = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(count);
}
/*
*
* JdbcTemplate.query(String sql, RowMapper<Employee> rowMapper, Object... args)
* queryForList()
*/
@Test
public void testQueryForList(){
String sql="SELECT id, name, email FROM employees WHERE id>?";
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
List<Employee> list = jdbcTemplate.query(sql,rowMapper,4);
System.out.println(list);
}
/*
* ,
* JdbcTemplate.queryForObject(String sql, Class<Employee> requiredType, Object... args)
* JdbcTemplate.queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
* 1.RowMapper , BeanPropertyRowMapper
* 2. sql
* 3. ,JdbcTemplate JDBC , ORM
*/
@Test
public void testQueryForObject(){
String sql="SELECT id, name, email FROM employees WHERE id=?";
// Employee employee = jdbcTemplate.queryForObject(sql, Employee.class,5);
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
Employee employee = jdbcTemplate.queryForObject(sql, rowMapper,3);
System.out.println(employee);
}
// , JdbcTemplate batchUpdate(String sql, List<Object[]> batchArgs)
@Test
public void testBatchUpdate(){
String sql = "INSERT INTO employees(name, email, dept_id) VALUES(?,?,?)";
List<Object[]> batchArgs= new ArrayList<>();
batchArgs.add(new Object[]{"jack2","[email protected]",5});
batchArgs.add(new Object[]{"jack3","[email protected]",5});
batchArgs.add(new Object[]{"jack4","[email protected]",5});
jdbcTemplate.batchUpdate(sql, batchArgs);
}
//INSERT , DELETE, UPDATE JdbcTemplate update()
@Test
public void testUpdate(){
String sql="INSERT employees VALUES(4,'yuchen','[email protected]',3)";
jdbcTemplate.update(sql);
sql = "UPDATE employees SET name=? WHERE id=?";
jdbcTemplate.update(sql, "jack",1);
sql="DELETE FROM employees WHERE id=?";
jdbcTemplate.update(sql, 1);
}
}
JdbcTemplateクラスのメソッド呼び出しは、実際に開発されたオブジェクトと組み合わせることができます.
Employeeのデータベース・アクセス・オブジェクトEmployeeDAOを作成し、idでEmployeeオブジェクトの情報を取得します.// , context:component-scan
@Repository
public class EmployeeDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
public Employee getEmployeeById(int id){
String sql = "SELECT id, name, email FROM employees WHERE id=?";
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
if(jdbcTemplate==null){
System.out.println("null");
}
Employee employee = jdbcTemplate.queryForObject(sql, rowMapper,id);
return employee;
}
@Test
public void testGetEmployeeById(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-jdbc.xml");
// EmployeeDAO IOC , new , jdbcTemplate
// new ,jdbcTemplate
EmployeeDAO employeeDAO = (EmployeeDAO) applicationContext.getBean("employeeDAO");
Employee employee = employeeDAO.getEmployeeById(3);
System.out.println(employee);
}
}
3、JdbcDaoSupportの使用
JdbcDaoSupportクラスはJdbcTemplateクラスと同様にspringフレームワークによるJdbcプログラミングのサポートですが、使い方が異なり、JdbcDaoSupportは実は呼び出されたJdbcTemplateクラスです.
JdbcDaoSupportを使用したデータベースの操作は、JdbcTemplateを直接使用するよりも煩雑であるため、属性としてJdbcTemplateクラスオブジェクトを使用してデータベース操作を行うのが一般的です.
JdbcDaoSupportを使用する方法:
JdbcDaoSupportの親を継承するクラスを作成します(注釈でIOCでbeanを生成します)
新しいメソッドを作成し、DataSourceプロパティを構成します.そうしないと、例外が発生します.(IOCにおけるdataSourceを注釈によりパラメータに自動化)
JdbcDaoSupportのgetJdbcTemplateメソッドを呼び出してJdbcTemplateオブジェクトを取得し、メソッドを呼び出して操作を完了します.// JdbcDaoSupport, JdbcTemplate
// JdbcDaoSupport , dataSource
@Repository
public class DepartmentDAO extends JdbcDaoSupport{
// JdbcDaoSupport setDataSource() finally, ,
// ,
@Autowired//
public void setDataSource2(DataSource dataSource){
setDataSource(dataSource);
}
public Department get(Integer id){
String sql= "SELECT id,dept_name name FROM department WHERE id = ?";
RowMapper<Department> rowMapper = new BeanPropertyRowMapper<>(Department.class);
// JdbcDaoSupprot JdbcTemplate
Department department = getJdbcTemplate().queryForObject(sql, rowMapper,id);
return department;
}
@Test
public void testGet(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-jdbc.xml");
DepartmentDAO departmentDAO = (DepartmentDAO) ctx.getBean("departmentDAO");
Department department = departmentDAO.get(1);
System.out.println(department);
}
}
注記でbeanを構成する場合は、springプロファイルにラベルを追加することを忘れないでください:context:component-scan base-package=""<context:component-scan base-package="com.cqupt.spring.jdbc"></context:component-scan>
4、NamedParameterJdbcTemplateの使用
NamedParameterJdbcTemplateは、JdbcTemplateと同様にデータベース操作のクラスであり、JdbcTemplateとは少し異なります.
String sql="INSERT INTO employees VALUES(?,?,?)";プレースホルダ、パラメータが多すぎる場合は、パラメータの対応する位置に特に注意する必要があり、不便であるため、パラメータを持つJdbcTemplateを導入する.
NamedParameterJdbcTemplateを使用するメリットは、パラメータの位置に対応する必要がなく、パラメータ名に直接対応することです. /*
* NamedParameterJdbcTemplate,
* : , ,
* :
*/
@Test
public void testNamedParameterJdbcTemplate(){
// String sql="INSERT INTO employees VALUES(?,?,?)";
String sql="INSERT INTO employees(name,email,dept_id) VALUES(:name,:email,:deptId)";
NamedParameterJdbcTemplate njt = (NamedParameterJdbcTemplate) applicationContext.getBean("namedParameterJdbcTemplate");
// Map
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("name", "zhangM");
paramMap.put("email", "[email protected]");
paramMap.put("deptId", 4);
njt.update(sql, paramMap);
//
// , , SqlParameterSource
//update(String sql, SqlParameterSource paramSource)
Employee employee = new Employee();
employee.setName("wangX");
employee.setEmail("[email protected]");
employee.setDeptId(5);
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee);
njt.update(sql, paramSource);
}
オブジェクトを使用して操作を完了する場合、名前付きパラメータの名前はオブジェクトの属性名と一致しなければならない.
4、事務管理
Springフレームワークはトランザクションにも対応する仕組みがあり、
Springはプログラミングトランザクション管理と宣言トランザクション管理をサポートし、宣言トランザクションはトランザクションに対する操作を非常に簡単に行うことができます.
プログラミングトランザクション管理とは、トランザクション管理のコードをビジネスメソッドに埋め込み、トランザクションのコミットとロールバックを制御することです.
宣言式トランザクション管理とは、トランザクション管理のコードをビジネスから分離し、トランザクション管理を宣言的に制御することです. Connection conn = null;
try{// :
conn = JDBCTools.getConnection();
// , false
conn.setAutoCommit(false);
String sql= "UPDATE users SET balance = balance+500 WHERE username = 'yuchen' ";
update(conn, sql);
int a =10/0;
sql= "UPDATE users SET balance = balance-500 WHERE username = 'jack'";
update(conn,sql);
// ,
conn.commit();
} catch (Exception e){
e.printStackTrace();
try {
// ,
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally{
JDBCTools.release(null,null, conn);
}
トランザクションのプログラミング式から,トランザクション管理はAOPと大きく類似していることが分かるため,springのAOPメカニズムを用いて宣言トランザクション管理をサポートする.
トランザクションはJDBCだけでなく、JTA(Java Transaction API)ではHibernateにそれぞれのトランザクションがあります.
Springは異なるトランザクション管理APIから一連のトランザクションメカニズムを抽象化し,開発者はこれらのトランザクションの下位APIを理解する必要がなく,これらのトランザクションメカニズムを利用することができる.これらのトランザクション・メカニズムにより、トランザクション管理コードは特定のトランザクション・テクノロジーから独立します.
Springのコアトランザクション管理の抽象は、Interface PlatformTransactionManagerです.
Jdbcの場合、DataSourceTransactionManagerがあり、アプリケーションでは1つのデータソースを処理し、JDBCでアクセスするだけです.
JTAについてはJtaTransactionManagerがあり、JavaEEアプリケーションサーバ上でJTAによるトランザクション管理が行われている(JTAについては詳細が必要)
Hibernateの場合、HibernateTransactionManagerがあり、Hibernateフレームワークでデータベースにアクセスします(Hibernateの詳細はこちら)
トランザクションマネージャは通常のBean形式でIOCコンテナに宣言します.
1つの例でトランザクションの詳細を完了します.
トランザクションの準備
1つの書店では、図書の販売、3つの要素があります:顧客の口座、図書の情報、図書の在庫.
口座:口座名、残高;
図書:書号、書名、価格;
在庫:本番号、在庫.
まず、BookShopDaoインタフェースを確立し、データベースに対する様々な操作を完了します.public interface BookShopDao {
//
public double findBookPriceByIsbn(String isbn);
// , -1
public void updateBookStock(String isbn);
// , username balance-price
public void updateUserAccount(String isbn, double price);
}
実装クラス@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public double findBookPriceByIsbn(String isbn) {
String sql = "SELECT price FROM book WHERE isbn=?";
double price = jdbcTemplate.queryForObject(sql, double.class,isbn);
return price;
}
@Override
public void updateBookStock(String isbn) {
// , , ( , mysq )
String sqlCheck = "SELECT stock FROM book_stock WHERE isbn = ?";
int stock = jdbcTemplate.queryForObject(sqlCheck, int.class,isbn);
if(stock == 0){
throw new BookStockException(" !");
}
String sql = "UPDATE book_stock SET stock = stock-1 WHERE isbn=?";
jdbcTemplate.update(sql, isbn);
}
@Override
public void updateUserAccount(String username, double price) {
// , ,
String sqlCheck = "SELECT balance FROM account WHERE username = ?";
double balance = jdbcTemplate.queryForObject(sqlCheck, double.class,username);
if(balance -price < 0){
throw new BookStockException(" !");
}
String sql = "UPDATE account SET balance = balance-? WHERE username=?";
jdbcTemplate.update(sql,price,username);
}
}
は、Junit試験ユニットを介して、BookShopDaoの様々な方法を検証することができる.
次に,業務に対する抽象クラスBookShopServiceを構築する.public interface BookShopService {
// , : 、
public void purchase(String username,String isbn);
}
実装クラス、BookShopDaoを呼び出すメソッド@Repository("bookShopService")
public class BookShopServiceImpl implements BookShopService{
@Autowired
private BookShopDao bookShopDao;
@Override
public void purchase(String username, String isbn) {
//
double price = bookShopDao.findBookPriceByIsbn(isbn);
//
bookShopDao.updateBookStock(isbn);
//
bookShopDao.updateUserAccount(username, price);
}
}
purchaseメソッドでは、残高が不足している場合に在庫を更新し、残高不足の異常を発見し、データベース内のデータが一致しない可能性があります.この場合,purchase()メソッドをトランザクションにするにはspringで提供されるトランザクションを利用する必要がある.
宣言トランザクション
使用方法:
1.springプロファイルでトランザクションマネージャを構成する
SpringのトランザクションマネージャはDataSourceTransactionManagerクラスです.構成時には、構築パラメータを指定して、管理するデータソースを指定する必要があります. <!-- , -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
.取引注釈の有効化
ネーミングスペースtxを導入し、ラベルでトランザクションマネージャを示す <!-- -->
<tx:annotation-driven transaction-manager="transactionManager"/>
3.注釈@Transactionalによって、一連の操作をトランザクションとして宣言する(メソッド) //
@Transactional
@Override
public void purchase(String username, String isbn) {
//
double price = bookShopDao.findBookPriceByIsbn(isbn);
//
bookShopDao.updateBookStock(isbn);
//
bookShopDao.updateUserAccount(username, price);
}
これでspringのトランザクション管理が完了しました
5、取引の属性
トランザクションの伝播動作
トランザクションの伝播行為とは?メソッドAはトランザクションであり、メソッドBもトランザクションであり、メソッドAでメソッドBを呼び出すと、トランザクションの伝播動作が形成される.
では、この場合、メソッドBはメソッドAのトランザクションを継続しますか、それともメソッドBは新しい独自のトランザクションを開き、メソッドAのトランザクションを一時的に保留しますか.
これがトランザクションの伝播動作の設定です.
設定方法:
メソッドBのトランザクション注釈には、トランザクションの伝播動作が2つ記載されています.
@Transactional(propagation=Propagation.REQUIRD)メソッドBは、他のトランザクションメソッドによって呼び出された場合、独自のトランザクションを作成する必要がなく、呼び出しメソッドを使用するトランザクションだけでよいのがデフォルトの伝播動作である.
@Transactional(propagation=Propagation.REQUIRES_NEW)メソッドBは、他のトランザクションメソッドによって呼び出されたときに、独自の新しいトランザクションを作成し、メソッドを呼び出すトランザクションを一時停止する.
注釈はインタフェースの方法や実装クラスの方法でも可能である.
使用例:
Cashierインタフェースを作成し、一度に複数の図書を購入し、チェックします.実装クラスCashierImplがBookShopServiceを呼び出すメソッドpublic interface Cashier {
//
public void checkout(String username, List<String> isbns);
}
実装クラス@Repository("cashier")
public class CashierImpl implements Cashier {
@Autowired
private BookShopService bookShopService;
@Transactional
@Override
public void checkout(String username, List<String> isbns) {
for(String isbn : isbns){
//purchase()
bookShopService.purchase(username,isbn);
}
}
}
では、checkoutメソッドはトランザクションであり、呼び出されたpurchaseメソッドもトランザクションである場合、purchaseメソッドのトランザクション注釈にトランザクションの伝播動作が明記される //
// propagation , REQUIRED,
// REQUIRES_NEW, , ,
// ,
@Transactional(propagation=Propagation.REQUIRES_NEW)
@Override
public void purchase(String username, String isbn) {
//
double price = bookShopDao.findBookPriceByIsbn(isbn);
//
bookShopDao.updateBookStock(isbn);
//
bookShopDao.updateUserAccount(username, price);
}
このとき、伝播挙動はREQUIRES_であるNEWは、purchaseメソッドが独自のトランザクションを作成することを示し、purchaseメソッドが異常である場合、ロールバック操作は自分のトランザクション内で完了し、checkoutのトランザクションに影響を及ぼさず、ステータスは現在のメソッドpurchaseが呼び出される前に戻ります.
伝播動作がREQUIRDの場合、purchaseメソッドがcheckoutを使用するトランザクションを表し、単一メソッドpurchaseに異常が発生し、ロールバック操作はcheckoutのトランザクション内で完了し、ステータスはcheckoutが呼び出されたステータスに戻る前に戻ります.
トランザクションの独立性レベル
トランザクションの独立性レベルは、JDBCの学習で詳しく説明されています.参照してください.最もよく使われるのは、「READ_COMMITTEDを読み、提出した」ということです.
Springの設定では、伝播属性のように、isolation=Isolation.READ_COMMITTEDを直接追加します.
ロールバックしない例外の指定
トランザクションのロールバックとは、トランザクションで例外が発生した場合に、ステータスがトランザクションの前のステータスにロールバックされることを意味します.
ロールバックしない例外を指定するのは、これらの例外が発生した場合、ロールバック操作を実行せず、他の指定されていない例外が発生した場合と同様にロールバック操作が必要です.
直接追加:noRollbackFor={xxxException.class}
読み取り専用プロパティ
読み取り専用属性を追加するのは、データベースをより効率的に操作するためです.同時に更新されたトランザクションを読み取り、最下位レベルではデータにロックをかけて独立性レベルに達する必要があります.読み取り専用属性として宣言すると、これらの操作は必要なく、データの読み取りがより効率的になります.
直接追加:readOnly=true/false
タイムアウト属性
トランザクションが長期にわたってリソースを占有できないようにするには、トランザクションが一定の時間を超えると、ロールバック操作を強制する必要があります.
timeout=3単位は秒 @Transactional(propagation=Propagation.REQUIRES_NEW,//
isolation=Isolation.READ_COMMITTED,//
noRollbackFor={AccountBalanceException.class},//
readOnly=false,//
timeout=3//
)
@Override
public void purchase(String username, String isbn) {
//
double price = bookShopDao.findBookPriceByIsbn(isbn);
//
bookShopDao.updateBookStock(isbn);
//
bookShopDao.updateUserAccount(username, price);
}
6、XMLファイルの形式で取引を配置する
DataSourceとJdbcTemplateのbeanを構成する前提で、カスタムクラスのbeanを構成し、トランザクションを構成します.
1.トランザクションマネージャのbeanの構成
2.トランザクションのプロパティを設定し、ラベルtx:adviceを使用してプロパティを指定します.関連するトランザクションマネージャ
3.トランザクションの切り込みポイントを構成し、トランザクションの切り込みポイントaop:pointcutとトランザクションのプロパティをaop:advisorに関連付け、関連するトランザクションのプロパティbeanを指定します.<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
<!-- -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!-- spring JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- bean -->
<bean id="bookShopDao" class="com.cqupt.spring.tx.xml.BookShopDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="bookShopService" class="com.cqupt.spring.tx.xml.service.impl.BookShopServiceImpl">
<property name="bookShopDao" ref="bookShopDao"></property>
</bean>
<bean id="cashier" class="com.cqupt.spring.tx.xml.service.impl.CashierImpl">
<property name="bookShopService" ref="bookShopService"></property>
</bean>
<!--1. , -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
<!-- 2. -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- tx:method , , , * -->
<tx:method name="purchase" propagation="REQUIRES_NEW"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<!-- , name="*",
, , -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 3. , -->
<aop:config>
<aop:pointcut expression="execution(* com.cqupt.spring.tx.xml.service.impl.*.*(..))"
id="txPintcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPintcut"/>
</aop:config>
</beans>