JdbcTemplate是spring框架中提供的一個模板對象,是對原始繁瑣的Jdbc API對象的簡單封裝。java
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
int update(); 執行增、刪、改語句 List<T> query(); 查詢多個 T queryForObject(); 查詢一個 new BeanPropertyRowMapper<>(); 實現ORM映射封裝
查詢數據庫全部帳戶信息到Account實體中mysql
public class JdbcTemplateTest { @Test public void testFindAll() throws Exception { // 建立核心對象 JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource()); // 編寫sql String sql = "select * from account"; // 執行sql List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class)); } }
基於Spring的xml配置實現帳戶的CRUD案例web
1. 建立java項目,導入座標 2. 編寫Account實體類 3. 編寫AccountDao接口和實現類 4. 編寫AccountService接口和實現類 5. 編寫spring核心配置文件 6. 編寫測試代碼
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.15</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.5.RELEASE</version> </dependency> </dependencies>
public class Account { private Integer id; private String name; private Double money; }
public interface AccountDao { public List<Account> findAll(); public Account findById(Integer id); public void save(Account account); public void update(Account account); public void delete(Integer id); }
@Repository public class AccountDaoImpl implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public List<Account> findAll() { // 編寫sql String sql = "select * from account"; // 執行sql return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class)); } @Override public Account findById(Integer id) { // 編寫sql String sql = "select * from account where id = ?"; // 執行sql return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class),id); } @Override public void save(Account account) { // 編寫sql String sql = "insert into account values(null,?,?)"; // 執行sql jdbcTemplate.update(sql, account.getName(), account.getMoney()); } @Override public void update(Account account) { // 編寫sql String sql = "update account set name = ?,money = ? where id = ?"; // 執行sql jdbcTemplate.update(sql, account.getName(), account.getMoney(),account.getId()); } @Override public void delete(Integer id) { // 編寫sql String sql = "delete from account where id = ?"; // 執行sql jdbcTemplate.update(sql, id); } }
public interface AccountService { public List<Account> findAll(); public Account findById(Integer id); public void save(Account account); public void update(Account account); public void delete(Integer id); }
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Override public List<Account> findAll() { return accountDao.findAll(); } @Override public Account findById(Integer id) { return accountDao.findById(id); } @Override public void save(Account account) { accountDao.save(account); } @Override public void update(Account account) { accountDao.update(account); } @Override public void delete(Integer id) { accountDao.delete(id); } }
<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.lagou"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean > <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean > <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> </beans>
@RunWith(SpringJUnit4Cla***unner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AccountServiceTest { @Autowired private AccountService accountService; //測試保存 @Test public void testSave() { Account account = new Account(); account.setName("lucy"); account.setMoney(100d); accountService.save(account); } //測試查詢 @Test public void testFindById() { Account account = accountService.findById(3); System.out.println(account); } //測試查詢全部 @Test public void testFindAll() { List<Account> accountList = accountService.findAll(); for (Account account : accountList) { System.out.println(account); } } //測試修改 @Test public void testUpdate() { Account account = new Account(); account.setId(3); account.setName("rose"); account.setMoney(2000d); accountService.update(account); } //測試刪除 @Test public void testDelete() { accountService.delete(3); } }
1. 建立java項目,導入座標 2. 編寫Account實體類 3. 編寫AccountDao接口和實現類 4. 編寫AccountService接口和實現類 5. 編寫spring核心配置文件 6. 編寫測試代碼
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.15</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.5.RELEASE</version> </dependency> </dependencies>
public class Account { private Integer id; private String name; private Double money; // setter getter.... }
public interface AccountDao { public void out(String outUser, Double money); public void in(String inUser, Double money); }
@Repository public class AccountDaoImpl implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void out(String outUser, Double money) { jdbcTemplate.update("update account set money = money - ? where name = ?", money, outUser); } @Override public void in(String inUser, Double money) { jdbcTemplate.update("update account set money = money + ? where name = ?", money, inUser); } }
public interface AccountService { public void transfer(String outUser, String inUser, Double money); }
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Override public void transfer(String outUser, String inUser, Double money) { accountDao.out(outUser, money); accountDao.in(inUser, money); } }
<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--IOC註解掃描--> <context:component-scan base-package="com.lagou"/> <!--加載jdbc配置文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--把數據庫鏈接池交給IOC容器--> <bean > <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--把JdbcTemplate交給IOC容器--> <bean > <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> </beans>
@RunWith(SpringJUnit4Cla***unner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void testTransfer() throws Exception { accountService.transfer("tom", "jerry", 100d); } }
Spring的事務控制能夠分爲編程式事務控制和聲明式事務控制。spring
開發者直接把事務的代碼和業務代碼耦合到一塊兒,在實際開發中不用。sql
開發者採用配置的方式來實現的事務控制,業務代碼與事務代碼實現解耦合,使用的AOP思想。數據庫
PlatformTransactionManager接口,是spring的事務管理器,裏面提供了咱們經常使用的操做事務的方法。編程
方法 | 說明 |
---|---|
TransactionStatus getTransaction(TransactionDefinition definition); | 獲取事務的狀態信息 |
void commit(TransactionStatus status); | 提交事務 |
void rollback(TransactionStatus status); | 回滾事務 |
* PlatformTransactionManager 是接口類型,不一樣的 Dao 層技術則有不一樣的實現類。 * Dao層技術是jdbcTemplate或mybatis時: DataSourceTransactionManager * Dao層技術是hibernate時: HibernateTransactionManager * Dao層技術是JPA時: JpaTransactionManager
TransactionDefinition接口提供事務的定義信息(事務隔離級別、事務傳播行爲等等)mybatis
方法 | 說明 |
---|---|
int getIsolationLevel() | 得到事務的隔離級別 |
int getPropogationBehavior() | 得到事務的傳播行爲 |
int getTimeout() | 得到超時時間 |
boolean isReadOnly() | 是否只讀 |
設置隔離級別,能夠解決事務併發產生的問題,如髒讀、不可重複讀和虛讀(幻讀)。併發
* ISOLATION_DEFAULT 使用數據庫默認級別 * ISOLATION_READ_UNCOMMITTED 讀未提交 * ISOLATION_READ_COMMITTED 讀已提交 * ISOLATION_REPEATABLE_READ 可重複讀 * ISOLATION_SERIALIZABLE 串行化
事務傳播行爲指的就是當一個業務方法【被】另外一個業務方法調用時,應該如何進行事務控制。app
參數 | 說明 |
---|---|
REQUIRED | 若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。通常的選擇(默認值) |
SUPPORTS | 支持當前事務,若是當前沒有事務,就以非事務方式執行(沒有事務) |
MANDATORY | 使用當前的事務,若是當前沒有事務,就拋出異常 |
REQUERS_NEW | 新建事務,若是當前在事務中,把當前事務掛起 |
NOT_SUPPORTED | 以非事務方式執行操做,若是當前存在事務,就把當前事務掛起 |
NEVER | 以非事務方式運行,若是當前存在事務,拋出異常 |
NESTED | 若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行REQUIRED 相似的操做 |
* read-only(是否只讀):建議查詢時設置爲只讀 * timeout(超時時間):默認值是-1,沒有超時限制。若是有,以秒爲單位進行設置
TransactionStatus 接口提供的是事務具體的運行狀態。
方法 | 說明 |
---|---|
boolean isNewTransaction() | 是不是新事務 |
boolean hasSavepoint() | 是不是回滾點 |
boolean isRollbackOnly() | 事務是否回滾 |
boolean isCompleted() | 事務是否完成 |
能夠簡單的理解三者的關係:事務管理器經過讀取事務定義參數進行事務管理,而後會產生一系列的事務狀態。
1)配置文件
<!--事務管理器交給IOC--> <bean > <property name="dataSource" ref="dataSource"/> </bean>
2)業務層代碼
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private PlatformTransactionManager transactionManager; @Override public void transfer(String outUser, String inUser, Double money) { // 建立事務定義對象 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // 設置是否只讀,false支持事務 def.setReadOnly(false); // 設置事務隔離級別,可重複讀mysql默認級別 def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); // 設置事務傳播行爲,必須有事務 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); // 配置事務管理器 TransactionStatus status = transactionManager.getTransaction(def); try { // 轉帳 accountDao.out(outUser, money); accountDao.in(inUser, money); // 提交事務 transactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); // 回滾事務 transactionManager.rollback(status); } } }
Spring中的事務控制主要就是經過這三個API實現的
* PlatformTransactionManager 負責事務的管理,它是個接口,其子類負責具體工做 * TransactionDefinition 定義了事務的一些相關參數 * TransactionStatus 表明事務運行的一個實時狀態
理解三者的關係:事務管理器經過讀取事務定義參數進行事務管理,而後會產生一系列的事務狀態。
在 Spring 配置文件中聲明式的處理事務來代替代碼式的處理事務。底層採用AOP思想來實現的。
聲明式事務控制明確事項:
使用spring聲明式事務控制轉帳業務。
1. 引入tx命名空間 2. 事務管理器通知配置 3. 事務管理器AOP配置 4. 測試事務控制轉帳業務代碼
1)引入tx命名空間
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w2.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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/s chema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> </beans>
2)事務管理器通知配置
<!--事務管理器--> <bean > <property name="dataSource" ref="dataSource"></property> </bean> <!--通知加強--> <tx:advice transaction-manager="transactionManager"> <!--定義事務的屬性--> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice>
3)事務管理器AOP配置
<!--aop配置--> <aop:config> <!--切面配置--> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.serivce..*.*(..))"> </aop:advisor> </aop:config>
4)測試事務控制轉帳業務代碼
@Override public void transfer(String outUser, String inUser, Double money) { accountDao.out(outUser, money); // 製造異常 int i = 1 / 0; accountDao.in(inUser, money); }
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/> * name:切點方法名稱 * isolation:事務的隔離級別 * propogation:事務的傳播行爲 * timeout:超時時間 * read-only:是否只讀
<tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="find*" read-only="true"/> <tx:method name="*"/> </tx:attributes>
* 平臺事務管理器配置 * 事務通知的配置 * 事務aop織入的配置
步驟分析
1. 修改service層,增長事務註解 2. 修改spring核心配置文件,開啓事務註解支持
步驟分析
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = -1, readOnly = false) @Override public void transfer(String outUser, String inUser, Double money) { accountDao.out(outUser, money); int i = 1 / 0; accountDao.in(inUser, money); } }
2)修改spring核心配置文件,開啓事務註解支持
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w2.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--省略以前datsSource、jdbcTemplate、組件掃描配置--> <!--事務管理器--> <bean > <property name="dataSource" ref="dataSource"></property> </bean> <!--事務的註解支持--> <tx:annotation-driven/> </beans>
核心配置類
@Configuration // 聲明爲spring配置類 @ComponentScan("com.lagou") // 掃描包 @Import(DataSourceConfig.class) // 導入其餘配置類 @EnableTransactionManagement // 事務的註解驅動 public class SpringConfig { @Bean public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean("transactionManager") public PlatformTransactionManager getPlatformTransactionManager(@Autowired DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
數據源配置類
@PropertySource("classpath:jdbc.properties") public class DataSourceConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
* 平臺事務管理器配置(xml、註解方式) * 事務通知的配置(@Transactional註解配置) * 事務註解驅動的配置 <tx:annotation-driven/>、@EnableTransactionManagement
應用上下文對象是經過 new ClasspathXmlApplicationContext(spring配置文件) 方式獲取的,可是每次從容器中得到Bean時都要編寫 new ClasspathXmlApplicationContext(spring配置文件) ,這樣的弊端是配置文件加載屢次,應用上下文對象建立屢次。 Version:0.9 StartHTML:0000000105 EndHTML:0000002684 StartFragment:0000000141 EndFragment:0000002644
解決思路分析: 在Web項目中,可使用ServletContextListener監聽Web應用的啓動,咱們能夠在Web應用啓動時,就加載Spring的配置文件,建立應用上下文對象ApplicationContext,在將其存儲到最大的域servletContext域中,這樣就能夠在任意位置從域中得到應用上下文ApplicationContext對象了。
上面的分析不用手動實現,Spring提供了一個監聽器ContextLoaderListener就是對上述功能的封裝,該監聽器內部加載Spring配置文件,建立應用上下文對象,並存儲到ServletContext域中,提供了一個客戶端工具WebApplicationContextUtils供使用者得到應用上下文對象。
因此咱們須要作的只有兩件事:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.1.5.RELEASE</version> </dependency>
<!--全局參數--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value>• </context-param> <!--Spring的監聽器--> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext); Object obj = applicationContext.getBean("id");