• 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);
        }

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

  • 相关阅读:
    反转字符串
    数组
    复杂度分析(二)
    复杂度分析(一)
    业务应该这么写--特性
    5种方法快速启动一个应用程序
    业务应该这么写--表达式树
    业务应该这么写--泛型
    业务应该这么写--异常处理
    关于关系型数据库外键,要减轻数据库压力的一些说法
  • 原文地址:https://www.cnblogs.com/baidawei/p/9084259.html
Copyright © 2020-2023  润新知