[Re] Spring-3(JdbcTemplate)
阿新 • • 發佈:2020-09-15
Spring 提供了 JdbcTemplate 以便捷地操作 DB。
CRUD 測試
導包
配置檔案
<!-- DAO 層元件自動裝配 JdbcTemplate: @Repository public class EmpDao { @Autowired JdbcTemplate jdbcTemplate; } --> <context:component-scan base-package="cn.edu.nuist"></context:component-scan> <!-- 引用外部屬性檔案;"classpath:" 固定寫法,引入類路徑下資源 --> <context:property-placeholder location="classpath:dbconfig.properties"/> <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> </bean> <!-- Spring 提供了一個類 JdbcTemplate,使用它來操作 DB --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> <!-- 配置一個具有 ‘具名引數’ 功能的 JdbcTemplate --> <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean>
測試
public class TestJDBC { ApplicationContext ioc = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class); NamedParameterJdbcTemplate namedParamJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class); // 8. 建立 EmpDao,自動裝配 JdbcTemplate 物件 @Test public void testEmpDao() { EmpDao empDao = ioc.getBean(EmpDao.class); Employee emp = new Employee(); emp.setEmpName("吳九"); emp.setSalary(5000); empDao.saveEmp(emp); empDao.saveEmp(emp); } // 7. 以SqlParameterSource形式傳入引數值 public void testSqlParameterSource() { String sql = "INSERT INTO employees(emp_name, salary) VALUES(:empName, :salary)"; Employee emp = new Employee(); emp.setEmpName("崔八"); emp.setSalary(5000); // SqlParameterSource BeanPropertySqlParameterSource int update = namedParamJdbcTemplate.update(sql , new BeanPropertySqlParameterSource(emp)); System.out.println(update); } /* 6. 使用帶有具名引數的 SQL 語句插入一條員工記錄,並以 Map 形式傳入引數值 佔位符引數:? 的順序不能亂,傳參的時候要注意 具名引數:具有名字的引數,引數不是佔位符了,而是一個變數名 語法格式 [:引數名] Spring 有一個支援具名引數功能的JdbcTemplate: NamedParameterJdbcTemplate */ public void insertWithMap() { String sql = "INSERT INTO employees(emp_name, salary) VALUES(:empName, :salary)"; Map<String, Object> paramMap = new HashMap<>(); paramMap.put("empName", "田七"); paramMap.put("salary", 5000); int update = namedParamJdbcTemplate.update(sql, paramMap); System.out.println(update); } // 5. 更新資料 public void testUpdate() { String sql = "UPDATE employees SET salary = ? WHERE emp_id = ?"; int update = jdbcTemplate.update(sql, 4000, 4); System.out.println(update); } // 4. 批量插入資料 public void testBatchAdd() { String sql = "INSERT INTO employees(emp_name, salary) VALUES(?, ?)"; // List<Object[]> // List.size: SQL 語句要執行的次數 // Object[]: 每次執行要用的引數 List<Object[]> batchArgs = new ArrayList<>(); batchArgs.add(new Object[] {"張三", 3000}); batchArgs.add(new Object[] {"李四", 3000}); batchArgs.add(new Object[] {"王五", 3000}); batchArgs.add(new Object[] {"趙六", 3000}); int[] updates = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(Arrays.toString(updates)); } // 3. 查詢單個數據 public void queryMaxSalary() { String sql = "SELECT MAX(salary) FROM employees"; int maxSalary = jdbcTemplate.queryForObject(sql, Integer.class); System.out.println(maxSalary); } /* * JavaBean 需要和 DB 中表的欄位名一致,否則無法完成封裝 * JdbcTemplate 在方法級別進行了區分 * > 查詢單個物件:template.queryForObject(),如果查詢不到就會拋異常 * > 查詢集合:template.query() */ // 2. 查詢多條記錄,封裝到 List public void queryMore() { String sql = "SELECT emp_id empId, emp_name empName, salary" + " FROM employees WHERE salary > ?"; // 封裝 List List<Employee> emps = jdbcTemplate.query(sql , new BeanPropertyRowMapper<>(Employee.class), 3000); System.out.println(emps); } // 1. 查詢 1 條記錄,封裝到 JavaBean public void queryOne() { String sql = "SELECT emp_id empId, emp_name empName, salary" + " FROM employees WHERE emp_id = ?"; Employee emp = jdbcTemplate.queryForObject(sql , new BeanPropertyRowMapper<>(Employee.class), 40); System.out.println(emp); } }
宣告式事務
事務管理程式碼的固定模式作為一種橫切關注點,可以通過 AOP 方法模組化,進而藉助 Spring AOP 框架實現宣告式事務管理。
這個事務管理器就可以在目標方法執行前後進行事務控制(事務切面)。我們目前使用 DataSourceTransactionManager 即可。
配置檔案
<!-- 事務控制--> <!-- 1. 配置事務管理器讓其進行事務管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 控制住資料來源 (控制事務實際就是控制住Connection) --> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 2. 開啟基於註解的事務控制模式(依賴 tx 名稱空間), 預設 transactionManager --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 3. 給事務方法加 @Transactional → 環繞通知Around -->
@Transactional
propagation
事務的傳播行為(事務的傳播 + 事務的行為),如果有多個事務進行巢狀執行,子事務是否和大事務共用一個事務(使用同一條連線)。
- 如果是 REQUIRED,則子事務的屬性都是繼承自大事務。
- REQUIRED 是將之前事務用的 Connection 傳遞過來
- REQUIRES_NEW 直接使用新的 Connection
isolation
事務的隔離級別。
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
timeout
- 超時屬性
- 事務超出指定時長(秒為單位) 後自動終止並回滾
readOnly
- 預設 false
- 可以進行事務優化
- 能加快查詢速度,不用管事務那堆操作了
- 如果設定為 true 後,做非查詢操作,會拋異常
rollback 相關
- 異常分類
- 執行時異常(非檢查異常):可以不用處理,預設都回滾
- 編譯時異常(檢查異常):預設不回滾
- 回滾相關屬性
- rollbackFor:出現哪些異常,事務可以不回滾
- rollbackForClassName
- noRollbackFor:原來不回滾的異常,指定讓其回滾
- noRollbackForClassName
基於 XML 配置的事務
- 依賴 tx、aop 名稱空間
- Spring 中提供事務管理器(事務切面),配置這個事務管理器
- 配置事務方法
- 告訴 Spring 哪些方法是事務方法 (事務切面按照我們的切入點表示式去切入事務方法)
<aop:config>
<aop:pointcut id="txPoint" expression="execution(* com.atguigu.ser*.*.*(..))"/>
<!-- 事務建議;事務增強 advice-ref:指向事務管理器的配置 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"/>
</aop:config>
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!-- 事務屬性 -->
<tx:attributes>
<!-- 指明哪些方法是事務方法:
切入點表示式只是說,事務管理器要切入這些方法,
至於哪些方法加事務,還需要使用 tx:method 來指定
-->
<tx:method name="*"/>
<tx:method name="checkout" propagation="REQUIRED" timeout="-1"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 都用;重要的用配置,不重要的用註解 -->