spring jdbc、事务(三)

spring整合jdbc

  spring中提供了一个可以操作数据库的对象(JDBCTemplate),对象封装了jdbc技术。

  1.使用spring整合jdbc需要jdbc驱动、c3p0连接池、spring-jdbc、spring-tx事务包。

  2.准备数据库

CREATE TABLE `david2018_db`.`UserInfo` (
  `Id` INT NOT NULL AUTO_INCREMENT,
  `UserName` VARCHAR(255) NULL,
  PRIMARY KEY (`Id`));

  3.src下新建配置文件c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!--默认配置-->
    <default-config>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config>

    <!--配置连接池mysql-->
    <named-config name="mysql">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/david2018_db</property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </named-config>

</c3p0-config>

  4.编写测试类

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        ComboPooledDataSource dataSource=new ComboPooledDataSource("mysql");

        //创建jdbc模板对象
        JdbcTemplate jt = new JdbcTemplate();
        //注入连接池
        jt.setDataSource(dataSource);

        //添加
        jt.update("insert into userinfo (userName) values ('david')");

        //修改
        jt.update("update userinfo set username = 'tom' where id = 1");



    }

  5.与spring整合 新建UserInfo实体类,IUserInfoDao接口,UserInfoDaoImpl实现类

package com.david.bean;

public class UserInfo {
    private Integer Id;
    private String UserName;

    public Integer getId() {
        return Id;
    }

    public void setId(Integer id) {
        Id = id;
    }

    public String getUserName() {
        return UserName;
    }

    public void setUserName(String userName) {
        UserName = userName;
    }
}
package com.david.dao;

import com.david.bean.UserInfo;

import java.util.List;

public interface IUserInfoDao {
    void save(UserInfo u);
    void update(UserInfo u);
    void delete(UserInfo u);
    UserInfo getUserById(Integer id);
    int getTotalCount();
    List<UserInfo> getUserList();
}
package com.david.dao;

import com.david.bean.UserInfo;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class UserInfoDaoImpl implements IUserInfoDao{
    //定义一个jdbc模板等着spring注入
    private JdbcTemplate jt;

    public JdbcTemplate getJt() {
        return jt;
    }

    public void setJt(JdbcTemplate jt) {
        this.jt = jt;
    }
    @Override
    public void save(UserInfo u) {
        String sql = "insert into userinfo (username) values (?)";
        jt.update(sql,u.getUserName());
    }

    @Override
    public void update(UserInfo u) {
        String sql = "update userinfo set username = ? where id = ?";
        jt.update(sql,u.getUserName(),u.getId());
    }

    @Override
    public void delete(UserInfo u) {
        String sql = "delete from userinfo where id = ?";
        jt.update(sql,u.getId());
    }

    @Override
    public UserInfo getUserById(Integer id) {
        String sql = "select * from userinfo where id = ?";
        return jt.queryForObject(sql, new RowMapper<UserInfo>() {
            @Override
            public UserInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                UserInfo u = new UserInfo();
                u.setId(rs.getInt("id"));
                u.setUserName(rs.getString("username"));
                return u;
            }
        },id);
    }

    @Override
    public int getTotalCount() {
        String sql = "select count(*) from userinfo";
        return jt.queryForObject(sql,Integer.class);
    }

    @Override
    public List<UserInfo> getUserList() {
        String sql = "select * from userinfo";
        return jt.query(sql, new RowMapper<UserInfo>() {
            @Override
            public UserInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                UserInfo u = new UserInfo();
                u.setId(rs.getInt("id"));
                u.setUserName(rs.getString("username"));
                return u;
            }
        });
    }
}

  6.将Dao配置到spring容器 不需要用c3p0-config.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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!--将连接池放入spring容器 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>
    <!--将JDBCTemplate放入spring容器 -->
    <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--将UserInfoDao放入spring容器 -->
    <bean name="userInfoDao" class="com.david.dao.UserInfoDaoImpl">
        <property name="jt" ref="jdbcTemplate"></property>
    </bean>
</beans>

  7.测试

public class Main {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserInfoDaoImpl userInfoDao = (UserInfoDaoImpl) ac.getBean("userInfoDao");

        //添加
        UserInfo u = new UserInfo();
        u.setUserName("salinna");
        userInfoDao.save(u);

        //修改
        UserInfo u1 = new UserInfo();
        u1.setId(1);
        u1.setUserName("black");
        userInfoDao.update(u1);

        //删除
        UserInfo u2 = new UserInfo();
        u2.setId(2);
        userInfoDao.delete(u2);

        //查询数量
        int totalCount = userInfoDao.getTotalCount();
        System.out.println(totalCount);

        //查询单个user
        UserInfo u3 = userInfoDao.getUserById(1);
        System.out.println(u3);

        //查询user列表
        List<UserInfo> userList = userInfoDao.getUserList();
        for(UserInfo u4 : userList){
            System.out.println(u4);
        }

    }
}

spring中aop事务

  spring中封装了事务管理代码:事务操作(打开事务、提交事务、回滚事务),因为在不同平台操作事务的代码各不相同,所以spring提供了一个接口PlatformTransactionManger该接口实现类有DataSourceTransactionManager,HibernateTransactionManager等。

  spring管理事务的属性

    1.事务的隔离性:1248选择哪个隔离级别级别

    2.是否只读:如果打开 本次操作不允许修改数据库中的数据

    3.事务传播行为:解决业务方法之间调用,事务应该如何处理

      3.1:TransactionDefinition.PROPAGATION_REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。

      3.2:TransactionDefinition.PROPAGATION_REQUIRES_NEW 创建一个新的事务,如果当前存在事务,则把当前事务挂起。

      3.3:TransactionDefinition.PROPAGATION_SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

      3.4:TransactionDefinition.PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

      3.5:TransactionDefinition.PROPAGATION_NEVER 以非事务方式运行,如果当前存在事务,则抛出异常。

      3.6:TransactionDefinition.PROPAGATION_MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

      3.7:TransactionDefinition.PROPAGATION_NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

    

创建数据表

CREATE TABLE `david2018_db`.`Account` (
  `Id` INT NOT NULL AUTO_INCREMENT,
  `UserName` VARCHAR(45) NULL,
  `Money` DOUBLE NULL,
  PRIMARY KEY (`Id`));

测试数据

insert into account (username,money) values ('david',1000);
insert into account (username,money) values ('jack',1000);

创建接口、实现类

package com.david.dao;

public interface IAccountDao {
    void addMoney(Integer id,Double money);

    void decreaseModeny(Integer id,Double money);
}
package com.david.dao;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

//继承JdbcDaoSupport 这个类就可以直接使用jdbctemplate对象了 不用定义属性 然后去注入了
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
    @Override
    public void addMoney(Integer id, Double money) {
        getJdbcTemplate().update("update account set money = money + ? where id = ?",money,id);
    }

    @Override
    public void decreaseModeny(Integer id, Double money) {
        getJdbcTemplate().update("update account set money = money - ? where id = ?",money,id);
    }
}

编写服务类

package com.david.service;

public interface IAccountService {
    void transfer(Integer from,Integer to,Double money);
}
package com.david.service;

import com.david.dao.IAccountDao;

public class AccountServiceImpl implements IAccountService {

    private IAccountDao ad;

    @Override
    public void transfer(Integer from, Integer to, Double money) {
        //减钱
        ad.decreaseModeny(from, money);
        //加钱
        ad.addMoney(to, money);
    }

    public IAccountDao getAd() {
        return ad;
    }

    public void setAd(IAccountDao ad) {
        this.ad = ad;
    }
}

编写配置文件注入

<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>

    <bean name="accountDao" class="com.david.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean name="accountService" class="com.david.service.AccountServiceImpl">
        <property name="ad" ref="accountDao"></property>
    </bean>

</beans>

编写测试代码

public class Main {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        AccountServiceImpl accountService = (AccountServiceImpl) ac.getBean("accountService");

        accountService.transfer(1,2,100D);

    }
}

现在是没有事务的,如果在减少钱后 发生异常 此时 钱没了, 对方还没收到.

    public void transfer(Integer from, Integer to, Double money) {
        //减钱
        ad.decreaseModeny(from, money);

        int i = 1 / 0;
        //加钱
        ad.addMoney(to, money);
    }

spring三种加入事务的方式:

  1.编码式(了解):

    <!--事务核心管理器,封装了所有事务操作。依赖连接池 -->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <!-- 编码式需要模板对象,依赖事务核心管理器 -->
    <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

</beans>

  在AccountService中定义一个transactionTemplate属性并生成get set方法

public class AccountServiceImpl implements IAccountService {

    private IAccountDao ad;
    private TransactionTemplate tt;
    ...

  在spring容器中 注入transactionTemplate

    <bean name="accountService" class="com.david.service.AccountServiceImpl">
        <property name="ad" ref="accountDao"></property>
        <property name="tt" ref="transactionTemplate"></property>
    </bean>

  编写事务代码-无需手写打开事务 提交事务

public class AccountServiceImpl implements IAccountService {

    private IAccountDao ad;
    private TransactionTemplate tt;

    @Override
    public void transfer(Integer from, Integer to, Double money) {

        tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {

                //减钱
                ad.decreaseModeny(from, money);

                int i = 1 / 0;
                //加钱
                ad.addMoney(to, money);

            }
        });

    }
...

  2.xml配置(aop):

导入aop包和依赖包,导入aop命名空间,配置通知,织入

<?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-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.xsd">
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>

    <bean name="accountDao" class="com.david.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean name="accountService" class="com.david.service.AccountServiceImpl">
        <property name="ad" ref="accountDao"></property>
    </bean>

    <!--事务核心管理器,封装了所有事务操作。依赖连接池 -->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--方法名 隔离级别 传播行为 是否只读-->
            <!--配置指定方法: -->
            <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <!--配置多个方法:通配符匹配 以什么开头的所有方法  -->
            <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="persist*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="modify*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="remove*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!--配置织入 -->
    <aop:config>
        <!--切入点 -->
        <aop:pointcut id="txPc" expression="execution(* com.david.service.AccountServiceImpl.*(..))"></aop:pointcut>
        <!--配置切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"></aop:advisor>
    </aop:config>

</beans>

  3.注解配置(aop):

使用注解也是要导包,命名空间,然后开启注解

<?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-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.xsd">
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>

    <bean name="accountDao" class="com.david.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean name="accountService" class="com.david.service.AccountServiceImpl">
        <property name="ad" ref="accountDao"></property>
    </bean>

    <!--事务核心管理器,封装了所有事务操作。依赖连接池 -->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启注解事务 -->
    <tx:annotation-driven></tx:annotation-driven>

</beans>

然后再service实现类使用Transactional注解

    @Override
    @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false)
    public void transfer(Integer from, Integer to, Double money) {
        //减钱
        ad.decreaseModeny(from, money);

        //加钱
        ad.addMoney(to, money);
    }

 也可以将注解加到类上 ,表示类中所有方法都开启事务。 优先级:方法上有先找方法的,方法没有才找类上的。

猜你喜欢

转载自www.cnblogs.com/baidawei/p/9084259.html
今日推荐