JdbcTemplate框架中提供的一个对象,是对原始Jdbc API对象的简单封装。作用是和数据化进行交互,实现对表的的CRUD操作。
搭建环境:
引入依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jzt</groupId> <artifactId>day04_spring_01jdbctemplate</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.4.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> </dependencies> </project>账户实体类:
package com.jzt.domain; import java.io.Serializable; /** * 账户实体类 */ public class Account implements Serializable { private Integer id; private String name; private Float money; public Integer getId() { return id; } public void setId(Integer 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 + '}'; } }jdbctemplate类:
package com.jzt.jdbctemplate; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; public class JdbcTemplateDemo { public static void main(String[] args) { //配置数据源 DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://192.168.31.121:3306/springtest"); dataSource.setUsername("root"); dataSource.setPassword("123456"); //创建jdbctemplate JdbcTemplate jdbcTemplate = new JdbcTemplate(); //设置数据源 jdbcTemplate.setDataSource(dataSource); //操作数据库 jdbcTemplate.execute("insert into account(name, money) values('ddd', 2000)"); } }下面我们通过xml配置的方式对上面进行改造:
新建beans.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 https://www.springframework.org/schema/beans/spring-beans.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> <property name="url" value="jdbc:mysql://192.168.31.121:3306/springtest"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean> </beans>测试类:
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate"); jdbcTemplate.execute("insert into account(name, money) values('eee', 3000)");下面我们是用JdbcTemplate来实现简单的CRUD操作:
package com.jzt.jdbctemplate; import com.jzt.domain.Account; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; public class JdbcTemplateDemo2 { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate"); // jdbcTemplate.execute("insert into account(name, money) values('eee', 3000)"); //保存 jdbcTemplate.update("insert into account(name, money) values('fff', 4000f)"); //更新 jdbcTemplate.update("update account set money=? where id = ?", 1500f, 1); //删除 jdbcTemplate.update("delete from account where id = ?", 2); //查询所有数据 List<Account> accountList = jdbcTemplate.query("select * from account where money > ?", new BeanPropertyRowMapper<Account>(Account.class), 1500f); //查询一条记录 Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), 1); //查询一行一列 int num = jdbcTemplate.queryForObject("select count(*) from account where money > ?", Integer.class, 2000f); } }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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置dao层--> <bean id="accountDao" class="com.jzt.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" value="jdbcTemplate"></property> </bean> <!--配置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> <property name="url" value="jdbc:mysql://192.168.31.121:3306/springtest"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean> </beans>使用:
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); IAccountDao accountDao = (IAccountDao) ac.getBean("accountDao"); List<Account> list = accountDao.findAll(); 通过上面对JdbcTemplate的简单使用,我们发现在Dao的实现类中有一些冗余代码,就是需要定义一个JdbcTemplate,然后才能使用,其实我们可以定义一个类,来专门生成JdbcTemplate,如下:
package com.jzt.dao.impl; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; //此类用于抽取Dao中的重复代码 public class JdbcDaoSupport { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; if(jdbcTemplate == null){ jdbcTemplate = createJdbcTemplate(dataSource); } } private JdbcTemplate createJdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } }对于Dao实现类,我们只要继承该类,就可以通过get方法来获取到jdbcTemplate就可以使用了:
package com.jzt.dao.impl; import com.jzt.dao.IAccountDao; import com.jzt.domain.Account; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao { // private JdbcTemplate jdbcTemplate; // // public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { // this.jdbcTemplate = jdbcTemplate; // } public void add(Account account) { getJdbcTemplate().update("insert into account(name, money) values(?, ?)", account.getName(), account.getMoney()); } public void update(Account account) { getJdbcTemplate().update("update account set name = ?, money = ? where id = ?", account.getName(), account.getMoney(), account.getId()); } public void delete(Integer id) { getJdbcTemplate().update("delect from account where id + ?", id); } public List<Account> findAll() { return getJdbcTemplate().query("select * from account", new BeanPropertyRowMapper<Account>(Account.class)); } public Account findOne(Integer id) { return getJdbcTemplate().queryForObject("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class)); } }修改xml配置文件:
<!--配置dao层--> <bean id="accountDao" class="com.jzt.dao.impl.AccountDaoImpl"> <!-- <property name="jdbcTemplate" value="jdbcTemplate"></property>--> <property name="dataSource" ref="datasource"></property> </bean>这样就可以了。
实际在Spring中就有这样的类来实现以上功能。该类就是JdbcDaoSupport。
这样我们在定义dao层实现时,就可以直接集成该类,来去除自己定义JdbcTemplate了。
缺点:
单继承,无法扩展;
使用继承JdbcDaoSupport时,无法使用相关注解了。
spring框架为我们提供了一组事务控制的接口,这组接口是在spring-tx-5.0.2RELEASE.jar中。
此接口是spring的事务控制管理器,它里面提供了我们常用的操作事务的方法,包含3个具体的操作,如下:
获取事务的状态信息
TransactionStatus getTransaction(TransactionDefinition definition)
提交事务
void commit(TransactionStatus status)
回滚事务
void rollback(TransactionStatus status)
我们在开发中,都是使用它的实现类,如下真正的管理实务的对象:
org.springframework.jdbc.datasource.DataSourceTransactionManager:使用spring JDBC或者iBatis进行持久化数据时使用。org.springframework.orm.hibernate5.HibernateTransactionManager:使用hibernate版本进行持久化数据时使用。 他是事务的定义信息对象,里面有如下方法:
获取事务对象名称:String getName()获取事务隔离级别:int getlsolationlevel()获取事务的传播行为:int getPropagationBehavior()获取事务超时时间:int getTimeout()获取事务是否只读:boolean isReadOnly()事务的隔离级别:
事物的传播行为:
超时时间:
默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
是否为只读事务:
建议查询为只读事务。
此接口提供的是事务具体的运行状态,方法介绍如下:
刷新事务:void flush()获取是否存在存储点:boolean hasSavepoint()获取事务是否完成:boolean isCompleted()获取事务是否为新的事务:boolean isNewTransaction()设置事务回滚:void setRollbackOnly()获取事务是否回滚:boolean isRollbackOnly()spring中基于xml的声明式事务控制配置步骤:
(1)配置事务管理器
<!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>(2)配置事务通知
此时我们需要导入事务约束:tx名称空间和约束,同时也需要aop的;
使用tx:advice标签配置事务通知:
属性:
id:给事务通知起一个唯一标识;
transaction-manager:给事务通知提供一个事务管理器引用;
<!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> ... </tx:advice> (3)配置AOP中通用事务点表达式
<!--配置aop--> <aop:config> <!--配置切入点表达式--> <aop:pointcut id="pt1" expression="execution(* com.jzt.service.impl.*.*(..))"/> ... </aop:config> (4)建立事务通知和切入点表达式的对应关系
<!--配置aop--> <aop:config> <!--配置切入点表达式--> <aop:pointcut id="pt1" expression="execution(* com.jzt.service.impl.*.*(..))"/> <!--配置切入点表达式和事务通知的对应关系--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor> </aop:config> (5)在事务通知tx:advice标签内部配置事务属性
issolation:指定事务的隔离级别。默认值是DEFAULT,表示使用是巨亏的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法查能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果制定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何一场都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
<!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--配置事务的属性--> <tx:attributes> <tx:method name="*" propagation="REQUIRED" read-only="false"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice>综合以上配置如下:
<!--配置事务管理器--> <bean id="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="*" propagation="REQUIRED" read-only="false"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice> <!--配置aop--> <aop:config> <!--配置切入点表达式--> <aop:pointcut id="pt1" expression="execution(* com.jzt.service.impl.*.*(..))"/> <!--配置切入点表达式和事务通知的对应关系--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor> </aop:config>基于注解的声明式事务步骤如下:
(1)配置事务管理器
(2)开启spring对注解事务的支持
(3)在需要事务支持的地方使用@Transactional注解
具体配置如下:
<?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/tx http://www.springframework.org/schema/tx/spring-tx.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"> <!--配置spring容器需要扫描的包--> <context:component-scan base-package="com.jzt"></context:component-scan> <!--配置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> <property name="url" value="jdbc:mysql://192.168.31.121:3306/springtest"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean> <!-- (1)配置事务管理器--> <!-- (2)开启spring对注解事务的支持--> <!-- (3)在需要事务支持的地方使用@Transactional注解--> <!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans>在需要事务支持的地方使用@Transactional注解:
package com.jzt.service.impl; import com.jzt.dao.IAccountDao; import com.jzt.domain.Account; import com.jzt.service.IAccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Service("accountService") @Transactional(propagation = Propagation.REQUIRED,readOnly = true) public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao iAccountDao; @Override @Transactional(propagation = Propagation.REQUIRED,readOnly = false) public void transfer(String sourceName, String targetName, float money) { Account accounSource = iAccountDao.findAccountByName(sourceName); if(accounSource == null){ System.out.println("转出用户不存在"); return; } Account accountTarget = iAccountDao.findAccountByName(targetName); if(accounSource == null){ System.out.println("转入用户不存在"); return; } if (accounSource.getMoney() < money){ System.out.println("转出用户金额不足"); return; } accounSource.setMoney(accounSource.getMoney() - money); accountTarget.setMoney(accountTarget.getMoney() + money); iAccountDao.updateAccount(accounSource); int num = 1 / 0; iAccountDao.updateAccount(accountTarget); } }