JdbcTemplate
在引入IOC和AOP模块的基础上在引入Data Access/Integration模块,同时也要讲数据库驱动引入
一般使用Maven引入spring-jdbc就会数据访问模块引入
基本使用
将jdbcTemplate对象交由SpringIOC容器管理,具体配置如下:
<?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">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!--使用Spring中提供的数据库连接池-->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <!--数据库驱动-->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/> <!--数据库连接URL-->
<property name="username" value="root"/> <!--数据库用户名-->
<property name="password" value="root"/> <!--数据库密码-->
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/> <!--注入连接池-->
</bean>
</beans>
下面测试数据库连接
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
jdbcTemplate.execute("create table test(id int,name varchar(20))"); //execute用于表级操作,无返回值,不常用
}
更新操作
方法名 | 描述 |
---|---|
int update(String sql,Object ...args) |
执行插入、删除和更新的SQL,args 为SQL中的占位符内容,返回影响行数 |
int[] batchUpdate(String[] sql,List<Object[]> args) |
执行多条更新SQL,args 为SQL中的占位符内容,与多条SQL顺序一一对应,返回每条SQL影响的行数 |
查询操作
查询单个简单数据项
方法名 | 描述 |
---|---|
T queryForObject(String sql,Class<T> clazz,Object ...args) |
执行SQL,返回单个字段值对象,类型由clazz 参数指定,args 为SQL中的占位符内容 |
List<T> queryForList(String sql,Class<T> clazz,Object ...args) |
执行SQL,返回一列单个字段值对象,类型由clazz 参数指定,args 为SQL中的占位符内容 |
查询复杂对象(Map)
方法名 | 描述 |
---|---|
Map<String,Object> queryForMap(String sql,Object ...args) |
执行查询SQL,并将结果处理成Map集合,args 为SQL中的占位符内容 |
List<Map<String,Object>> queryForList(String sql,Object ...args) |
执行查询SQL,并将结果处理成Map的List集合,args 为SQL中的占位符内容 |
查询复杂对象(实体)
方法名 | 描述 |
---|---|
T queryForObject(String sql,RowMapper<T> rm,Object ...args) |
执行查询SQL,并将结果处理成JavaBean,一般使用BeanPropertyRowMapper(Class clazz) 对象,该类构造接收一个JavaBean类对象 |
List<T> query(String sql,RowMapper<T> rm,Object ...args) |
执行查询SQL,并将结果处理成JavaBean的List集合,一般使用BeanPropertyRowMapper(Class clazz) 对象,该类构造接收一个JavaBean类对象 |
手动实现RowMapper接口,对于连接查询可能会用到
jdbcTemplate.queryForObject("select * form students where id = 1", new RowMapper<Student>() {
@Override
public Student mapRow(ResultSet resultSet, int i) throws SQLException {
//resultSet是JDBC的结果集,i是处理的当前行号
//一般使用就向下面这样,从结果集中取出数据赋值给对象,在返回即可
Student student = new Student();
student.setStuId(resultSet.getInt("stu_id"));
student.setStuName(resultSet.getString("stu_name"));
return student;
}
});
事务
Spring中的事务接口架构
Spring将事务抽象成3个接口,分别是事务属性定义接口、事务管理器接口,事务状态接口,其中事务管理其接口的实现有多种,大致流程就是定义好事务属性,事务管理器执行事务改变事务状态
事务属性
- 回滚规则:默认情况下,事务遇到运行期异常(RuntimeException及其子类)自动回滚,而在遇到检查型异常(IOException、SQLException、FileNotFoundException等)时不回滚
- 事务超时时间:事务在特定时间内为完成,则自动回滚,默认是-1,不会超时
- 只读事务:利用数据库事务只读属性进行特定的优化处理,对于不同的数据库行为可能不同,Oracle的更新语句将不起作用,而MySQL的更新语句将会抛出异常
- 事务隔离级别:定义是否可接收脏读、不可重复读、幻读
ISOLATION_DEFAULT
:使用数据库默认的隔离级别ISOLATION_READ_UNCOMMITTED
:读未提交ISOLATION_READ_COMMITTED
:读已提交ISOLATION_REPEATABLE_READ
:可重复读ISOLATION_SERIALIZABLE
:串行化读
- 事务传播行为:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播
PROPAGATION_REQUIRED
:必须,当前方法必须允许在事务中,若当前事务存在,则在该事务中运行,否则会创建一个新事务PROPAGATION_SUPPORTS
:忍受,当前方法无需事务上下文,但若当前事务存在,就在改事务中运行,不存在也无所谓PROPAGATION_MANDATORY
:强制,当前方法必须在事务中运行,若当前事务不存在会抛出异常PROPAGATION_REQUIRED_NEW
:当前方法必须允许在自己的事务中,若当前事务存在,则在该方法执行期间,当前事务会被挂起PROPAGATION_NOT_SUPPORTS
:当前方法不应该运行在事务中,若存在当前事务,则在该方法执行期间,当前事务会被挂起PROPAGATION_NEVER
:当前方法不应该运行在事务上下文中,若当前事务存在,会抛出异常PROPAGATION_NESTED
:若当前事务存在,该方法将在嵌套事务中运行,若当前事务不存在,那么会创建一个新事务
事务管理器
根据给定的规则(事务属性)进行事务的提交或回滚
- JDBC事务管理器:使用连接对象控制,局限与一个数据库连接内,但使用简单
- JTA事务管理器:与实现无关,与协议无关的API,功能强大,可跨越多个数据库或DAO,使用比较复杂
- 等等
事务状态
用于描述当前事务的运行状态,通过事务管理器获取事务状态实例
事务管理器方式
public static void main(String[] args) throws PropertyVetoException {
/*1.创建数据源*/
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
/*2.创建JDBC事务管理器*/
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
/*3.创建事务管理器属性对象,根据需要,设置事务管理器的相关属性*/
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition(); // 定义事务属性
defaultTransactionDefinition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 设置传播行为属性
/*4.获得事务状态对象*/
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(defaultTransactionDefinition);
/*5.根据事务管理器获取的数据源,创建JdbcTemplate对象*/
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceTransactionManager.getDataSource());
try {
jdbcTemplate.update("update students set stu_sex = 1 where stu_id = 1");
dataSourceTransactionManager.commit(transactionStatus); //提交事务
} catch (Exception e) {
dataSourceTransactionManager.rollback(transactionStatus); //回滚事务
e.printStackTrace();
}
}
模板事务方式
无返回值的事务
public static void main(String[] args) throws PropertyVetoException {
/*1.创建数据源*/
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
/*2.创建JDBC事务管理器*/
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
/*3.更根据事务管理器,创建事务模板对象,根据需要,设置事务的相关属性*/
TransactionTemplate transactionTemplate = new TransactionTemplate(dataSourceTransactionManager);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED); //设置事务隔离级别
/*4.使用事务模板执行事务*/
transactionTemplate.execute(new TransactionCallbackWithoutResult() { //无返回值的事务使用TransactionCallbackWithoutResult接口实现其内部类
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { //transactionStatus是事务状态对象,用于事务回滚
try {
/*使用JdbcTemplate数据库操作*/
// JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// jdbcTemplate.execute("insert into students(stu_name,stu_sex) value('张三',0)");
/*使用简单模板化新增数据,不常用了解一下*/
SimpleJdbcInsert simpleInsert = new SimpleJdbcInsert(dataSource);
simpleInsert.withTableName("students").usingColumns("stu_name", "stu_sex");
Map<String, Object> parameters = new HashMap<>();
parameters.put("stu_name", "张三");
parameters.put("stu_sex", 1);
simpleInsert.execute(parameters);
//没有遇到异常,事务自动提交
} catch (Exception e) {
transactionStatus.setRollbackOnly(); //回滚事务
e.printStackTrace();
}
}
});
}
有返回值的事务
public static void main(String[] args) throws PropertyVetoException {
/*1.创建数据源*/
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
/*2.创建JDBC事务管理器*/
PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
/*3.更根据事务管理器,创建事务模板对象,根据需要,设置事务的相关属性*/
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED); //设置事务隔离级别
/*4.使用事务模板执行事务*/
Map<String, Object> map = transactionTemplate.execute(new TransactionCallback<Map<String, Object>>() { //有返回值的事务使用TransactionCallback接口实现其内部类,该泛型就是返回值类型
public Map<String, Object> doInTransaction(TransactionStatus transactionStatus) { //transactionStatus是事务状态对象,用于事务回滚
Map<String, Object> map = new HashMap<>();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
try {
map = jdbcTemplate.queryForMap("select * from students where stu_id = 1");
//没有遇到异常,事务自动提交
} catch (Exception e) {
transactionStatus.setRollbackOnly(); //回滚事务
e.printStackTrace();
}
return map;
}
});
System.out.println(map); //输出事务返回值
}
声明时事务方式
基于AOP机制,对方法前后进行拦截,通过配置就可以完成对事务的管理,自动提交或回滚事务
xml方式(tx拦截器)
<?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.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!--
首先在aop约束文件的基础上,添加 xmlns:tx="http://www.springframework.org/schema/tx" 约束文件
再在 xsi:schemaLocation属性后增加 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
之后使用下面标签才能有代码提示
-->
<!--使用Spring中提供的数据库连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--jdbcTemplate注入连接池-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--创建jdbc事务管理器,注入连接池-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--要自动执行事务提交和回滚的类-->
<bean id="userDaoImpl" class="com.UserDaoImpl"/>
<!--根据jdbc事务管理器,创建事务通知-->
<tx:advice id="dataSourceTransactionManagerAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes> <!--配置事务属性-->
<tx:method name="get*" read-only="true"/> <!--以get开头的方法,设置为只读事务-->
<tx:method name="*"/> <!--其他方法使用默认的事务属性即可-->
</tx:attributes>
</tx:advice>
<!--使用aop对事务方法进行代理-->
<aop:config>
<aop:advisor advice-ref="dataSourceTransactionManagerAdvice" pointcut="execution(* com.UserDaoImpl.*())"/>
</aop:config>
</beans>
下面是测试代码
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDaoImpl implements UserDao {
@Override
public void transaction() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
jdbcTemplate.update("update students set stu_sex = 1 where stu_id = 1");
}
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDaoImpl"); //必须从IOC容器中获取
userDao.transaction(); //执行事务方法
}
}
注解方式
<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--使用Spring中提供的数据库连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--jdbcTemplate注入连接池-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--jdbc事务管理器注入连接池-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--要自动执行事务提交和回滚的类-->
<bean id="userDaoImpl" class="com.UserDaoImpl"/>
<!--启动使用注解实现声明式事务管理的支持-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
</beans>
下面是测试代码
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
@Transactional() //使用该注解进行声明事务,该注解中也可配置事务的属性
//该注解可作用于类和公共方法上,作用于类上时表示该类下的所有公共方法增加事务功能
public class UserDaoImpl implements UserDao {
@Override
public void transaction() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
jdbcTemplate.update("update students set stu_sex = 1 where stu_id = 1");
}
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDaoImpl"); //必须从IOC容器中获取
userDao.transaction(); //执行事务方法
}
}
Comments NOTHING