Spring入门后半部分----JDBCTemplate和事务控制


查询单条数据


ApplicationContext app = new ClassPathXmlApplicationContext(“appOfDao.xml”);

JdbcTemplate jt = app.getBean(JdbcTemplate.class);

String sql=“SELECT MAX(money) FROM account”;

//无论是返回单个数据还是单个对象,都是调用queryForObject

Integer moneyMax = jt.queryForObject(sql, Integer.class);

System.out.println(“最高工资为:”+moneyMax);

在这里插入图片描述


使用带有具名参数的sql语句插入一条员工记录,并以Map的形式传入参数值


具名参数: (具有名字的参数,参数不是一个占位符了,而是以个变量名)

语法格式 --------------------> :参数名

需要使用spring的一个支持具名参数的springTemplate类

占位符参数: ?的顺序不能乱,传参的时候要注意

以map的形式传入参数

代码:

ApplicationContext app = new ClassPathXmlApplicationContext(“appOfDao.xml”);

JdbcTemplate jt = app.getBean(JdbcTemplate.class);

NamedParameterJdbcTemplate npjt = app.getBean(NamedParameterJdbcTemplate.class);

String sql=“insert into account(name,money) values(:name,:money)”;

//将有具名参数的值都放在map容器中

Map<String, Object> Map = new HashMap<String,Object>();

Map.put(“name”,“大忽悠”);

Map.put(“money”,8000);

int row = npjt.update(sql,Map);

System.out.println(“影响的行数:”+row);

在这里插入图片描述


以SqlParameterSource的形式传入参数

使用该方法前,要确保自定义类中有get方法,因为该方法实现原理是从传入的对象中,找对象的get方法,去掉get,首字母小写,看得到的字符串是否和具名参数匹配.

ApplicationContext app = new ClassPathXmlApplicationContext(“appOfDao.xml”);

JdbcTemplate jt = app.getBean(JdbcTemplate.class);

NamedParameterJdbcTemplate npjt = app.getBean(NamedParameterJdbcTemplate.class);

String sql=“insert into account(name,money) values(:name,:money)”;

friend f=new friend();

f.setMoney(20000);

f.setName(“小朋友”);

int row = npjt.update(sql, new BeanPropertySqlParameterSource(f));

System.out.println(“影响的行数”+row);

在这里插入图片描述


使用注解完成对JdbcTemplate的注入----小规模常用

test类:

@Component(“test”)

public class test {

@Autowired //按照类型注入

private JdbcTemplate jdbcTemplate;

int getJBDCTemplate(friend f)

{

int row = jdbcTemplate.update(“insert into account values(?,?)”, f.getName(), f.getMoney());

return row;

}

}

jdbc测试类:

ApplicationContext app = new ClassPathXmlApplicationContext(“appOfDao.xml”);

test t=(test)app.getBean(“test”);

friend f=new friend();

f.setName(“超级大忽悠”);

f.setMoney(40000);

int row = t.getJBDCTemplate(f);

System.out.println(“影响的行数”+row);

配置文件:

<context:component-scan base-package=“com.jdbcTemplate”/>

在这里插入图片描述


声明式事务

====================================================================

数据库环境搭建—账户表,图书表,图书库存表


account账号表:

在这里插入图片描述

book图书表:

在这里插入图片描述

book_stock图书库存表:

在这里插入图片描述

jdbc.properties的配置文件


jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/tx

jdbc.username=root

jdbc.password=126433

数据源配置并直接注入到jdbcTemplate中


<context:property-placeholder location=“classpath:jdbc.properties”/>

<context:component-scan base-package=“com.BookCheck”/>

Dao层和Service层的类环境搭建


BookDao类:

@Repository

public class BookDao {

@Autowired

private JdbcTemplate jdbcTemplate;

/减去某个用户的剩余金额/

public void updateBalance(String username,int price)

{

String sql=“update account set money=money-? where name=?”;

jdbcTemplate.update(sql,price,username);

}

/获取某本图书的价格/

public int getBookPrice(String isbn)

{

String sql=“select price from book where ISBN=?”;

return jdbcTemplate.queryForObject(sql, Integer.class,isbn);

}

/减去某本书库存/

public void updateStock(String isbn)

{

String sql=“update book_stock set stock=stock-1 where isbn=?”;

jdbcTemplate.update(sql,isbn);

}

}

Service类:

@Service

public class BookService {

@Autowired

BookDao bookDao;

/结账/

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}

}

主类:

public class test {

static ApplicationContext ioc= new ClassPathXmlApplicationContext(“appOfDao.xml”);

public static void main(String[] args) {

BookService bs = ioc.getBean(BookService.class);

bs.checkOut(“大忽悠”,“ISBN_001”);

System.out.println(“结账成功”);

}

}

在这里插入图片描述


声明式事务

====================================================================

事务管理器(事务切面)


Spring只是个容器,因此它并不做任何事务的具体实现。他只是提供了事务管理的接口PlatformTransactionManager,具体内容由就由各个事务管理器来实现。

在这里插入图片描述

事务管理器可以在目标方法运行前后进行事务控制

目前使用DataSourceTransactionManager

第一步:配置事务管理器,让其进行事务控制

第二步: 开启基于注解的事务控制模式,依赖tx命名空间

<tx:annotation-driven transaction-manager=“transactionManager”/>

第三步:给事务方法加上注解即可

加上注解之后,如果事务方法里面出现异常,那么整个事务方法会进行回滚,数据恢复原样

在这里插入图片描述


@Transactional注解里面的属性分析


timeout---->参数值为int(秒为单位),超时,事务超出指定执行时长后自动终止并回滚

@Transactional(timeout = 3)

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}


readOnly---->参数值为bool,设置事务为只读,可以进行事务优化,默认readOnly=false,改为readOnly=true后,可以加快查询速度,因此不用管事务的相关操作了(设置自动提交…)

如果事务方法中有增删改相关操作,还设置为true时,运行时会报错

/结账/

@Transactional(readOnly = false)

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}


异常分类

在这里插入图片描述

noRollbackFor---->参数值为Class[] (字节码文件类型,是个数组) ,那些异常事务可以不回滚

noRollbackForClassName---->参数值为String[] (全类名) ,那些异常事务可以不回滚

可以让原来默认回滚的异常给它不回滚

@Transactional(noRollbackFor ={ArithmeticException.class,NullPointerException.class} )

//数学异常不回滚,空指针异常不回滚

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}


rollbackFor---->参数值为Class[] (字节码文件类型) ,哪些异常事务需要回滚

rollbackForClassName---->参数值为String[] (全类名),哪些异常事务需要回滚

原本不回滚的异常指定让其回滚,原本编译时异常不会回滚

@Transactional(rollbackFor = {FileNotFoundException.class})

//文件异常回滚

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}


ioslation调整隔离级别

前置知识:数据库事务并发问题

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

同时对一个数据进行修改(并发修改同一个数据下的排队,挨个按照顺序进行修改操作)

在这里插入图片描述

前置知识:隔离级别

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


前置知识:查询mysql的隔离级别

在这里插入图片描述

前置知识:事务操作

在这里插入图片描述

前置知识:修改mysql的隔离级别

例如:

set [session|global] transaction isolation level read uncommitted


有事务的业务逻辑,容器中保存的是这个业务逻辑的代理对象(了解即可)

在这里插入图片描述


事务传播行为(事务的传播和事务的行为)


如果有多个事务同时进行嵌套运行,子事务是否要和大事务共同用一个事务

在这里插入图片描述

在这里插入图片描述


简单理解: 一个事务相等于一辆车,如果子事务和大事务共同用一个事务,那么可以理解为子事务和大事务位于同一辆车上。如果子事务开启一个新事务,相当于子事务开了一辆新车,大事务和子事务位于不同的车上面

在这里插入图片描述

注意: 出现的异常回一层一层往上面进行传递,坐一辆车的全崩,开新车并且在异常之前执行的不崩;开新车,但是位于异常之后,崩。

注意:如果子事务出现了异常,并且子事务位于大事务的方法体内部,那么大事务会感受到异常,那么即便大事务和子事务开不同的车,大事务也会崩掉,因为方法体内部出现了异常

子事务只和上一级的事务坐一辆车,不会和上一级的上一级的事务坐一辆车,除非他的上一级的事务和他的上一级的上一级的事务坐一辆车

总结图

在这里插入图片描述


设置事务传播行为演示

@Repository

public class BookDao {

@Autowired

private JdbcTemplate jdbcTemplate;

/减去某个用户的剩余金额/

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void updateBalance(String username,int price)

{

String sql=“update account set money=money-? where name=?”;

jdbcTemplate.update(sql,price,username);

}

/获取某本图书的价格/

public int getBookPrice(String isbn)

{

String sql=“select price from book where ISBN=?”;

return jdbcTemplate.queryForObject(sql, Integer.class,isbn);

}

/减去某本书库存/

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void updateStock(String isbn)

{

String sql=“update book_stock set stock=stock-1 where isbn=?”;

jdbcTemplate.update(sql,isbn);

}

}

@Transactional(propagation = Propagation.REQUIRED)

//文件异常回滚

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}

在这里插入图片描述


重点:REQUIRED事务属性来源于大事务(子事务和大事务坐一辆车时),即子事务的所有属性,例如超时设置,回滚设置,都继承于大事务,即使子事务里面设置了,也没有用

propagation = Propagation.REQUIRES_NEW可以调整,默认是REQUIRED


REQUIRED将之前事务使用的connection传递给这个事务使用

REQUIRED_NEW这个方法直接使用新的connection


本类事务方法之间的调用就只是一个事务

@Transactional

@Service

public class BookService {

@Autowired

BookDao bookDao;

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void checkOut(String username,String isbn)

{

//1.减去库存

bookDao.updateStock(isbn);

//2.获取图书的价格

int bookPrice = bookDao.getBookPrice(isbn);

//3.减去余额

bookDao.updateBalance(username,bookPrice);

}

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void updateStock(String isbn)

{

bookDao.updateStock(isbn);

}

@Transactional

void testmain()

{

checkOut(“大忽悠”,“ISBN_001”);

updateStock(“ISBN_002”);

System.out.println(“结账成功”);

int i=10/0;

}

}

主类:

public static void main(String[] args) {

ApplicationContext ioc= new ClassPathXmlApplicationContext(“appOfDao.xml”);

BookService bs = ioc.getBean(BookService.class);

//虽然testmain里面的两个方法都开了新车,

//但是testmain方法最后出现了异常,效果并不如预期般改变(即回滚了事务)

bs.testmain();

}

原因:代理对象调用方法的时候,才能实现事务的控制

在这里插入图片描述

在这里插入图片描述

无法进行事务控制,也就相当于无法通过动态代理,对方法进行增强的操作,无法进行增强的操作,当然也就无法进行事务控制了


在本类中给本类对象进行注入,会造成死循环

在这里插入图片描述

死循环原因: IOC容器创建时,先去实例化BookService对象,实例化BookService时,发现需要给其成员变量bookService装配对象,为了给成员变量装配对象,会去容器中找对应类型的对象,结果找到了还没创建的对象BookService对象(还没创建是因为正在为其成员变量赋值),于是又去给他创建对象…


事务控制的xml配置:依赖tx名称空间和aop名称空间


要导入spring-tx坐标,spring处理事务相关的坐标


切点方法事务配置参数


在这里插入图片描述

1.引入依赖

org.aspectj

aspectjweaver

1.8.4

org.springframework

spring-context

5.0.5.RELEASE

org.springframework

spring-test

5.0.5.RELEASE

junit

junit

4.13.1

mysql

mysql-connector-java

5.1.32

c3p0

c3p0

0.9.1.2

com.alibaba

druid

1.1.10

org.springframework

spring-jdbc

5.0.5.RELEASE

org.springframework

spring-tx

5.0.5.RELEASE

2.开启注解扫描—引入context命名空间

<context:component-scan base-package=“com.BookCheck”/>

3.引入properties配置文件

<context:property-placeholder location=“classpath:jdbc.properties”/>

4.创建数据源dataSource

惊喜

最后还准备了一套上面资料对应的面试题(有答案哦)和面试时的高频面试算法题(如果面试准备时间不够,那么集中把这些算法题做完即可,命中率高达85%+)

image.png

image.png

加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
sion>

com.alibaba

druid

1.1.10

org.springframework

spring-jdbc

5.0.5.RELEASE

org.springframework

spring-tx

5.0.5.RELEASE

2.开启注解扫描—引入context命名空间

<context:component-scan base-package=“com.BookCheck”/>

3.引入properties配置文件

<context:property-placeholder location=“classpath:jdbc.properties”/>

4.创建数据源dataSource

惊喜

最后还准备了一套上面资料对应的面试题(有答案哦)和面试时的高频面试算法题(如果面试准备时间不够,那么集中把这些算法题做完即可,命中率高达85%+)

[外链图片转存中…(img-4RjgPZcu-1725509685244)]

[外链图片转存中…(img-gx1QkpKK-1725509685245)]

加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值