Spring 学习4

Spring 学习4

JdbcTemplate

学习 JdbcTemplate,它是 Spring 提供的一个对象,是对原始 Jdbc API 对象的简单封装,Spring 为我们提供了很多的操作模板类。

操作关系型数据的: JdbcTemplate HibernateTemplate
操作 nosql 数据库的: RedisTemplate
操作消息队列的: JmsTemplate

pom.xml 文件添加依赖

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <!--mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <!--jdbc依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <!--事务相关依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
    </dependencies>

创建演示数据库表

CREATE DATABASE `spring_note`;
USE spring_note;
CREATE TABLE `t_account`(
`id` INT(8) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` FLOAT(8) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

创建实体类

public class Account implements Serializable {
    private int id;
    private String name;
    private float money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getMoney() {
        return money;
    }

    public void setMoney(float money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

数据库操作要用到数据源,如c3p0,Druid等,Spring 提供了一个内置数据源,这里就用内置数据源演示。

public class AppNoteDemo {

    public static void main(String[] args) {
         //Spring 内置数据源
        DriverManagerDataSource dataSource=new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring_note");
        dataSource.setUsername("root");//数据库用户名
        dataSource.setPassword("root");//数据库密码
        //创建JdbcTemplate对象
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        //给jdbcTemplate设置数据源
        jdbcTemplate.setDataSource(dataSource);
        //执行操作,这里演示插入数据操作
        jdbcTemplate.execute("insert into t_account(name,money) values('apple',100)");

    }
}

Spring 学习4

(id为2是因为之前删了1的数据,不重要)

写在 java 代码里的配置信息可以写进 XML 配置文件里的

bean.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:aop="http://www.springframework.org/schema/aop"
       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/aop
             http://www.springframework.org/schema/aop/spring-aop.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--配置数据源-->
    <bean id="dataSource" 
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_note"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    
</beans>

启动类

public class AppNoteDemo {

    public static void main(String[] args) {

        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        JdbcTemplate jdbcTemplate=ac.getBean("jdbcTemplate",JdbcTemplate.class);
        //执行操作,这里演示插入数据操作
        jdbcTemplate.execute("insert into t_account(name,money) values('a1',100)");

    }
}

Spring 学习4

JdbcTemplate 简易增删查改操作

增加

public class AppNoteDemo {

    public static void main(String[] args) {

        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        JdbcTemplate jdbcTemplate=ac.getBean("jdbcTemplate",JdbcTemplate.class);
        //执行操作,这里演示插入数据操作
        jdbcTemplate.execute("insert into t_account(name,money) values('a1',100)");

    }
}

更新

jdbcTemplate.update("update  t_account set money=? where id=?",200,6);

删除

jdbcTemplate.update("delete from  t_account where id=?",6);

查询全部

List<Account> accountList=jdbcTemplate.query("select * from t_account where money> ?",new BeanPropertyRowMapper<Account>(Account.class),100);

参数2:<Account>泛型为你查询到的数据对应实体类,(Account.class) 为你数据对应实体类的字节码

参数3:参数1 SQL 语句的?位置的数据

查询1条数据

List<Account> accountList=jdbcTemplate.query("select * from t_account where id= ?",new BeanPropertyRowMapper<Account>(Account.class),4);
        System.out.println(accountList.get(0));

返回1条数据,所以列表里第0个数据就是查到的那1条数据。

查询1行1列,使用聚合函数但不加group by语句

int returnValue=jdbcTemplate.queryForObject("select count(*) from t_account where money > ?",Integer.class,100);

参数2:你查询的数据是什么类型就用什么类型的字节码,这里查询到的是个整数就用 Integer.class

参数3:参数1 SQL 语句的?位置的数据

JdbcTemplate 常用增删查改操作(放在dao里)

IAccountDao 接口:(这里只用2个数据操作方法演示,其他方法都类似)

public interface IAccountDao {

    //根据id查询
    Account findAccountById(int id);
    //更新数据
    int updateAccount(Account account);
}

AccountDaoImpl 类,实现 IAccountDao 接口

public class AccountDaoImpl implements IAccountDao {

    private JdbcTemplate jdbcTemplate;

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

    @Override
    public Account findAccountById(int id) {
        List<Account> accountList=jdbcTemplate.query("select * from t_account where id= ?",new BeanPropertyRowMapper<Account>(Account.class),5);
        return accountList.get(0);
    }

    @Override
    public int updateAccount(Account account) {
        return jdbcTemplate.update("update  t_account set money=? where id=?",account.getMoney(),account.getId());
    }
}

启动类

public class AppNoteDemo {

    public static void main(String[] args) {

        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        IAccountDao accountDao=ac.getBean("accountDao",IAccountDao.class);
        Account account=accountDao.findAccountById(5);
        System.out.println("根据id查询:"+account);

        account.setMoney(1000);
        System.out.println("更新数据的数量:"+accountDao.updateAccount(account));

    }
}

Spring 学习4

改进写法

实际开发中会写多个dao实现类,这些类里都会有这些重复部分

private JdbcTemplate jdbcTemplate;

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

JdbcDaoSupport 是Spring 提供的一个类,该类中定义了一个 JdbcTemplate 对象,我们可以直接获取使用,但是想创建该对象,需要为其提供一个数据源。

AccountDaoImpl 类修改一下

public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {


    @Override
    public Account findAccountById(int id) {
        List<Account> accountList=getJdbcTemplate().query("select * from t_account where id= ?",new BeanPropertyRowMapper<Account>(Account.class),5);
        return accountList.get(0);
    }

    @Override
    public int updateAccount(Account account) {
        return getJdbcTemplate().update("update  t_account set money=? where id=?",account.getMoney(),account.getId());
    }
}

bean.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:aop="http://www.springframework.org/schema/aop"
       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/aop
             http://www.springframework.org/schema/aop/spring-aop.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置dao-->
    <bean id="accountDao" class="com.rgb3.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置数据源-->
    <bean id="dataSource" 
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_note"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

</beans>

第一种方式在 Dao 类中定义 JdbcTemplate ,适用于 XML 配置方式和注解配置方式。第二种用继承的方式,只能用 XML 配置方式。

JdbcTemplate 事务控制(XML配置方式)

例子演示

还是引入上面一样的依赖,数据库表,Account 实体类、IAccountDao 接口和上面的一样。

AccountDaoImpl 类

public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
    @Override
    public Account findAccountById(int id) {
        List<Account> accountList=getJdbcTemplate().query("select * from t_account where id= ?",new BeanPropertyRowMapper<Account>(Account.class),id);
        return accountList.get(0);
    }

    @Override
    public int updateAccount(Account account) {
        return getJdbcTemplate().update("update  t_account set money=? where id=?",account.getMoney(),account.getId());
    }
}

IAccountService 接口

public interface IAccountService {
    void transfer(int sourceId, int targetId,float money);
}

AccountServiceImpl 类

//@Service("accountService")
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao;
    public void setAccountDao(IAccountDao accountDao){
        this.accountDao=accountDao;
    }

    @Override
    public void transfer(int sourceId, int targetId, float money) {
        //1.根据名称查询两个账户
        Account source = accountDao.findAccountById(sourceId);
        Account target = accountDao.findAccountById(targetId);
        //2.修改两个账户的金额
        source.setMoney(source.getMoney()- money);//转出账户减钱
        target.setMoney(target.getMoney()+ money);//转入账户加钱
        // 3.更新两个账户
        accountDao.updateAccount(source);
        int i=1/0;		//故意设置异常
        accountDao.updateAccount(target);
    }
}

bean.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/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
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置service-->
    <bean id="accountService" class="com.rgb3.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--配置dao-->
    <bean id="accountDao" class="com.rgb3.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_note"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--事务的配置-->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" read-only="false" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
    
    <!--配置 AOP-->
    <aop:config>
        <!--配置切入点表达式-->
        <aop:pointcut id="pt1" expression="execution(* com.rgb3.service.impl.*.*(..))"/>
        <!--事务的建议与切入点表达式建立联系-->
        <aop:advisor advice-ref="transactionAdvice" pointcut-ref="pt1"/>
    </aop:config>
</beans>

配置事务时可以填的属性:

<tx:attributes>
            <tx:method name="*" read-only="false" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
        </tx:attributes>

read-only:是否是只读事务。默认 false,表示读写。

isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。

propagation:指定事务的传播行为。默认值 REQUIRED 表示一定会有事务,增删改操作可以选这个,值 SUPPORTS 查询方法可以选这个。

timeout:指定超时时间。默认值为:-1。永不超时。

rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。 没有默认值,任何异常都回滚。

no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。

name="*":*为通配符,表示所有方法

name=“find*”:表示含有 find 方法名的方法(所以命名方法时注意规范)

启动类

public class AppNoteDemo {

    public static void main(String[] args) {

        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        IAccountService accountService=ac.getBean("accountService",IAccountService.class);
        accountService.transfer(5,3,100);
    }
}

启动前

Spring 学习4

启动后报错,并且数据库里的数据没有任何改变,事务控制成功。

Spring 学习4

JdbcTemplate 事务控制(注解配置方式)

数据库表与上面的一样。

AccountDaoImpl 类

@Repository("accountDao")
public class AccountDaoImpl  implements IAccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public Account findAccountById(int id) {
        List<Account> accountList=jdbcTemplate.query("select * from t_account where id= ?",new BeanPropertyRowMapper<Account>(Account.class),id);
        return accountList.get(0);
    }

    @Override
    public int updateAccount(Account account) {
        return jdbcTemplate.update("update  t_account set money=? where id=?",account.getMoney(),account.getId());
    }
}

AccountServiceImpl 类

@Service("accountService")
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class AccountServiceImpl implements IAccountService {

    @Autowired
    private IAccountDao accountDao;

    @Override
    @Transactional(readOnly = false,propagation = Propagation.REQUIRED)
    public void transfer(int sourceId, int targetId, float money) {
        //1.根据名称查询两个账户
        Account source = accountDao.findAccountById(sourceId);
        Account target = accountDao.findAccountById(targetId);
        //2.修改两个账户的金额
        source.setMoney(source.getMoney()- money);//转出账户减钱
        target.setMoney(target.getMoney()+ money);//转入账户加钱
        // 3.更新两个账户
        accountDao.updateAccount(source);
        //int i=1/0;  //故意设置异常
        accountDao.updateAccount(target);
    }
}

@Transactional

配置事务的属性可以填在里面,该注解的属性和 XML配置方式中的属性含义一致。该注解可以出现在接口上,上和方法上。

  • 出现接口上,表示该接口的所有实现类都有事务支持。
  • 出现在类上,表示类中所有方法有事务支持
  • 出现在方法上,表示这个方法有事务支持。
  • 以上三个位置的优先级:方法>类>接口。

JdbcConfig 配置类

//jdbc配置类
public class JdbcConfig {

    @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(name ="jdbcTemplate")
    public JdbcTemplate creaJdbcTemplate(DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }
	//配置数据源
    @Bean(name="dataSource")
    public DataSource createDataSource(){
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}

TransactionConfig 配置类

//事务配置类
public class TransactionConfig {

    //创建事务管理器对象
    @Bean(name = "transactionManager")
   public PlatformTransactionManager createTransactionManager(DataSource dataSource){
       return new DataSourceTransactionManager(dataSource);
   }
}

注意:导入 DataSource 类时选择这个:

import javax.sql.DataSource;

jdbcConfig.properties 配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_note
jdbc.username=root
jdbc.password=root

MySpringConfiguration 配置类

@Configuration
@ComponentScan("com.rgb3")	//开启扫描包位置
@Import({JdbcConfig.class,TransactionConfig.class})//导入其他配置类
@PropertySource("jdbcConfig.properties")	//属性配置文件
@EnableTransactionManagement    //开启事务控制管理
public class MySpringConfiguration {
}

启动前:

Spring 学习4

启动程序,成功转账

Spring 学习4

在AccountServiceImpl 类里故意设置异常测试一下

public void transfer(int sourceId, int targetId, float money) {
        //1.根据名称查询两个账户
        Account source = accountDao.findAccountById(sourceId);
        Account target = accountDao.findAccountById(targetId);
        //2.修改两个账户的金额
        source.setMoney(source.getMoney()- money);//转出账户减钱
        target.setMoney(target.getMoney()+ money);//转入账户加钱
        // 3.更新两个账户
        accountDao.updateAccount(source);
        int i=1/0;  //故意设置异常
        accountDao.updateAccount(target);
    }

启动出现异常,数据没有变化,成功事务控制。

Spring 学习4

上一篇:JdbcTemplate


下一篇:jdbcTemplate测试报错:没有合适的驱动