spring 基礎(四) spring jdbc

springJDBC在事務管理方面更佔優點,同時處理速度也比mybatis快一點。java

本文代碼連接mysql

1.基礎

  1. Spring JDBC是Spring框架用於處理關係型數據庫的模塊。
  2. Spring JDBC對JDBC API進行封裝,極大簡化開發工做量。
  3. JdbcTemplate是Spring JDBC核心類,提供數據CRUD方法。
  4. Mybatis做爲orm框架,封裝程度較高,適合敏捷開發。
  5. Jdbc使用步驟:
    Maven工程弓|入依賴spring-jdbc
    applicationContext.xml配置DataSource數據源
    在Dao注入JdbcTemplate對象,實現數據CRUDgit

  6. CURD:查詢有多種,可是刪除、修改、新增都是用update
  7. demo:

1:首先在pom中引入如下包spring

    <dependencies>
<!--        spring ioc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
<!--spring jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
<!--mysql引入-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>

<!--        單元測試-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>

<!--        單元測試 框架-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2:建立一個實體sql

public class Employee {
    private Integer eno;
    private String ename;
    private Float salary;
    private String dname;
    private Date hiredate;

    public Integer getEno() {
        return eno;
    }

    public void setEno(Integer eno) {
        this.eno = eno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Float getSalary() {
        return salary;
    }

    public void setSalary(Float salary) {
        this.salary = salary;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "eno=" + eno +
                ", ename='" + ename + '\'' +
                ", salary=" + salary +
                ", dname='" + dname + '\'' +
                ", hiredate=" + hiredate +
                '}';
    }
View Code

3:建立dao數據庫

public class EmployeeDao {
    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 根據id查找數據
     * queryForObject 返回單條數據
     *
     * @param eno
     * @return
     */
    public Employee findById(Integer eno) {
        String sql = "SELECT * FROM employee WHERE eno = ?";
        //查詢單條數據  若是有多個條件,則  new Object[]{eno,eno2,eno3} 數組中的順序對應着sql中問好的順序
        Employee employee = jdbcTemplate.queryForObject(sql, new Object[]{eno}, new BeanPropertyRowMapper<Employee>(Employee.class));
        return employee;
    }

    /**
     * query 返回list
     *
     * @param depName
     * @return
     */
    public List<Employee> findByName(String depName) {
        String sql = "SELECT * FROM employee WHERE dname = ?";
        List<Employee> query = jdbcTemplate.query(sql, new Object[]{depName}, new BeanPropertyRowMapper<Employee>(Employee.class));
        return query;
    }

    /**
     * queryForList 返回map集合數據 ,當返回的字段名字是entity中沒有的時候就使用這個
     * @param depName
     * @return
     */
    public List<Map<String, Object>> findMapByName(String depName) {
        String sql = "SELECT eno  enoAs,ename enameAs,salary salaryAs,dname  dnameAs FROM employee WHERE dname = ?";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, new Object[]{"depName"});
        return maps;
    }


    public void insert(Employee employee){
        String sql = "insert into employee(eno,ename,salary,dname,hiredate) values(?,?,?,?,?)";
        //利用update方法實現數據寫入操做
        jdbcTemplate.update(sql,new Object[]{
                employee.getEno() , employee.getEname(),employee.getSalary(),employee.getDname() , employee.getHiredate()
        });
    }

    public int update(Employee employee){
        String sql = "UPDATE employee SET ename = ?, salary = ?, dname = ?, hiredate = ? WHERE eno = ?";
        int count = jdbcTemplate.update(sql, new Object[]{employee.getEname(), employee.getSalary(), employee.getDname(), employee.getHiredate(), employee.getEno()});
        return count;
    }

    public int delete(Integer eno){
        String sql = "delete from employee where eno = ?";
        return jdbcTemplate.update(sql, new Object[]{eno});
    }

}

 4:建立serviceexpress

public class EmployeeService {
    private EmployeeDao employeeDao;
    private DataSourceTransactionManager transactionManager;
    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }
    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }
    public DataSourceTransactionManager getTransactionManager() {
        return transactionManager;
    }
    public void setTransactionManager(DataSourceTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
    //編程性事務
    public void batchImport(){
        //定義了事務默認的標準配置
        TransactionDefinition definition = new DefaultTransactionDefinition();
        //開始一個事務,返回事務狀態,事務狀態說明當前事務的執行階段
        TransactionStatus status = transactionManager.getTransaction(definition);
        try {
            for (int i = 1; i <= 10; i++) {
                /*if (i == 3) {   throw new RuntimeException("意料以外的異常");   }*/
                Employee employee = new Employee();
                employee.setEno(8000 + i);
                employee.setEname("員工" + i);
                employee.setSalary(4000f);
                employee.setDname("市場部");
                employee.setHiredate(new Date());
                employeeDao.insert(employee);
            }
            transactionManager.commit(status); //提交事務
        }catch (RuntimeException e){
            transactionManager.rollback(status);  //回滾事務
            throw e;
        }

    }
}
View Code

 

5:建立applicationContext.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--    數據源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://localhost:33068/imooc?useSSL=false&amp;useUnicode=true&amp;
                  characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/>
        <property name="password" value="Ee123"/>
    </bean>

    <!--    JdbcTemplate提供數據CRUD的api-->
    <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="employeeDao" class="com.item.spring.jdbc.dao.EmployeeDao">
        <!--爲Dao注入JdbcTemplate對象-->
        <property name="jdbcTemplate" ref="JdbcTemplate"/>

    </bean>


<!--   編程性 事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <bean id="employeeService" class="com.item.spring.jdbc.service.EmployeeService">
        <property name="employeeDao" ref="employeeDao"/>
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
</beans>

6:建立一個測試類api

/**
 * @RunWith+ @ContextConfiguration做用= ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
 *
 */
@RunWith(SpringJUnit4ClassRunner.class) //JUnit 控制權交給spring
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class JdbctemplateTestor {
    @Resource
    private EmployeeDao employeeDao;
    @Resource
    private EmployeeService employeeService;
    @Test
    public void textFindById(){
        Employee byId = employeeDao.findById(3308);
        System.out.println(byId);
    }

    @Test
    public void findByName(){
        List<Employee> list = employeeDao.findByName("研發部");
        System.out.println(list);
    }

    @Test
    public void findMapByName(){
        List<Map<String, Object>> map = employeeDao.findMapByName("研發部");
        System.out.println(map);
    }

    @Test
    public void testBatchImport(){
        employeeService.batchImport();
        System.out.println("批量導入成功");
    }
}

 

 

 

2.spring事務管理

  1. 事務是以一種可靠的、-致的方式,訪問和操做數據庫的程序單元;簡單理解:要麼把事情作完,要麼什麼都不作,不要作一半。
  2. 事務依賴於數據庫實現,MySQL經過事務區做爲數據緩衝地帶。

2.1spring編程式事務

  1. 基礎
    1. 編程式事務是指經過代碼手動提交回滾事務的事務控制方法。
    2. SpringJDBC經過TransactionManager事務管理器實現事務控制。
    3. 事務管理器提供commit/rollback方法進行事務提交與回滾。
    4. 優勢是程序中好控制,缺點是程序中容易人爲破壞。
    5. 事務中執行sql始終用一條數據庫鏈接。執行多條sql,前面sql執行完畢以後放在事務區中,等待所有執行完畢以後決定是提交仍是回滾。
  2. demo,已經在上面展現,主要實在service中以及applicationContext.xml中配置:

2.2spring聲明式事務

  1. 聲明式事務指在不修改源碼狀況下經過配置形式自動實現事務控制,聲明式事務本質就是AOP環繞通知。
  2. 當目標方法執行成功時,自動提交事務。
  3. 當目標方法拋出運行時異常時,自動事務回滾。
  4. 因爲聲明式事務都是再xml文件中配置,指定那些名稱方法執行事務,這個命名帶來規範性同時也限制住了命名規則。
  5. 配置過程:
    1.   配置TransactionManager事務管理器
    2.   配置事務通知與事務屬性
    3.   爲事務通知綁定PointCut切點、
  6. demo(基礎代碼和前面案例同樣,就不展現。主要顯示編程事務):

1:applicationContext.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: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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!-- 數據源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://localhost:33068/imooc?useSSL=false&amp;useUnicode=true&amp;
                  characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/>
        <property name="password" value="Ee123"/>
    </bean>


    <!--JdbcTemplate提供數據CRUD的API-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="employeeDao" class="com.item.springJdbc.dao.EmployeeDao">
        <!--爲Dao注入JdbcTemplate對象-->
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
    <bean id="batchService" class="com.item.springJdbc.service.BatchService">
        <property name="employeeDao" ref="employeeDao"/>
    </bean>
    <bean id="employeeService" class="com.item.springJdbc.service.EmployeeService">
        <property name="employeeDao" ref="employeeDao"/>
        <property name="batchService" ref="batchService"/>
    </bean>

<!-- 
此處事務的做用域是com.item下任何子子孫孫/子包,只要文件是Service結尾,的方法都將使用到事務。而具體是某些方法在<tx:advice id="txAdvice" transaction-manager="transactionManager">中配置
<tx:method name="batchImport" propagation="REQUIRED"/> 說明只要方法名是batchImport,都將使用事務

--> <!-- 1.事務管理器,用於建立事務/提交/回滾 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--2.事務通知配置,決定哪些方法使用事務,哪些方法不使用事務 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 目標方法名爲batchImport時,啓用聲明式事務,成功提交,運行時異常回滾 --> <tx:method name="batchImport" propagation="REQUIRED"/> <tx:method name="batch*" propagation="REQUIRED"/> <!-- 設置全部findXXX方法不須要使用事務 --> <tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true"/> <tx:method name="get*" propagation="NOT_SUPPORTED" read-only="true"/> <tx:method name="importJob1" propagation="REQUIRES_NEW"/> <tx:method name="importJob2" propagation="REQUIRES_NEW"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--3. 定義聲明式事務的做用範圍--> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.item..*Service.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/> </aop:config> </beans>

2:service文件

public class EmployeeService {
    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }

    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }

    public BatchService getBatchService() {
        return batchService;
    }

    public void setBatchService(BatchService batchService) {
        this.batchService = batchService;
    }

    private EmployeeDao employeeDao;
    private BatchService batchService;

    public void batchImport() {
        for (int i = 1; i <= 10; i++) {
//此處代碼爲測試事務使用
// if(i==3){ // throw new RuntimeException("意料以外的異常"); // } Employee employee = new Employee(); employee.setEno(8000 + i); employee.setEname("員工" + i); employee.setSalary(4000f); employee.setDname("市場部"); employee.setHiredate(new Date()); employeeDao.insert(employee); } } public void startImportJob(){ batchService.importJob1(); if(1==1){ throw new RuntimeException("意料以外的異常"); } batchService.importJob2(); System.out.println("批量導入成功"); } }

2.3spring註解式事務

  1. 註解事務最大的好處是再也不去xml文件中配置,哪一個方法/類想使用事務就只用標記就行
  2. demo:

 

 

 

 applicationContext.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: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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="com.item"/>
    <!--數據源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://localhost:33068/imooc?useSSL=false&amp;useUnicode=true&amp;
                  characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/>
        <property name="password" value="Ee123"/>
    </bean>
    <!--JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 啓用註解形式聲明式事務 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

service:

@Service
//聲明式事務核心註解
//放在類上,將聲明式事務配置應用於當前類全部方法,默認事務傳播爲 REQUIRED
@Transactional
public class EmployeeService {
    @Resource
    private EmployeeDao employeeDao;
    @Resource
    private BatchService batchService;

    @Transactional(propagation = Propagation.NOT_SUPPORTED , readOnly = true)
    public Employee findById(Integer eno){
        return employeeDao.findById(eno);
    }

    public void batchImport() {
        for (int i = 1; i <= 10; i++) {
            if(i==3){
                throw new RuntimeException("意料以外的異常");
            }
            Employee employee = new Employee();
            employee.setEno(8000 + i);
            employee.setEname("員工" + i);
            employee.setSalary(4000f);
            employee.setDname("市場部");
            employee.setHiredate(new Date());
            employeeDao.insert(employee);
        }
    }

    public void startImportJob(){
        batchService.importJob1();
        if(1==1){
            throw new RuntimeException("意料以外的異常");
        }
        batchService.importJob2();
        System.out.println("批量導入成功");
    }

    public EmployeeDao getEmployeeDao() {
        return employeeDao;
    }

    public void setEmployeeDao(EmployeeDao employeeDao) {
        this.employeeDao = employeeDao;
    }

    public BatchService getBatchService() {
        return batchService;
    }

    public void setBatchService(BatchService batchService) {
        this.batchService = batchService;
    }
}

3.事務的傳播行爲

  1. 事務傳播行爲是指多個擁有事務的方法在嵌套調用時的事務控制方式
  2. XML: < tx:method name=」..」 propagation="REQUIRED"/>
  3. 註解:@Transactional(propagation= Propagation.REQUIRED)
  4. 事務傳播行爲七種類型:
    1. PROPAGATION_REQUIRED(默認) :若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是最多見的選擇.也是系統默認。
    2. PROPAGATION_SUPPORTS:支持當前事務,若是當前沒有事務,就以非事務方式執行
    3. PROPAGATION_MANDATORY:使用當前的事務,若是當前沒有事務,就拋出異常
    4. PROPAGATION_REQUIRES_NEW:新建事務,若是當前存在事務,把當前事務掛起
    5. PROPAGATION_NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起
    6. PROPAGATION_NEVER:以非事務方式執行,若是當前存在事務,則拋出異常
    7. PROPAGATION_NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與PROPAGATION_REQUIRE相似的操做

 

 

 至關於只有一個事務

 

即使多個事務放在一塊兒執行,也是多個事務。每一個事務間互不影響

 

相關文章
相關標籤/搜索