事务
1编程式事务
2声明式事务
基于注解的声明式事务
1,配置xml文件
<!--1加载properties配置文件信息 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 2配置扫描包 --> <context:component-scan base-package="com.offcn"></context:component-scan> <!-- 3配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.userName}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> </bean> <!-- 4配置jdbcTemplate对象 --> <bean class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--5配置数据源资源管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 6开启基于注解的事务支持 --> <tx:annotation-driven transaction-manager="transactionManager"/>
2.在service层的方法上加@Transactional注解
3.具体操作
public class Book { private String isbn; private String book_name; private double price; public String getIsbn() { return isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public String getBook_name() { return book_name; } public void setBook_name(String book_name) { this.book_name = book_name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Book [isbn=" + isbn + ", book_name=" + book_name + ", price=" + price + "]"; } }
@Repository public class BookDao { @Autowired private JdbcTemplate jdbcTemplate; //得到书的价格 public double selectByBookname(String isbn) { String sql="select price from book where isbn=?"; return jdbcTemplate.queryForObject(sql, Double.class, isbn); } //使书的库存-1 public boolean updateStock(String isbn) { String sql="update book_stock set stock = stock-1 where isbn=?"; return jdbcTemplate.update(sql, isbn)>0?true:false; } //买书者的余额=钱数-书的价格 public void updateBalance(String username,double price) { String sql = "update account set balance = balance-? where username=?"; jdbcTemplate.update(sql,price,username); } }
@Service public class BookService { @Autowired private BookDao bookDao; @Transactional public void buyBook(String isbn,String username) { double price = bookDao.selectByBookname(isbn); boolean updateStock = bookDao.updateStock(isbn); bookDao.updateBalance(username, price); } }
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:bean.xml")//相当于ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”) public class App { @Autowired private BookService bookService; @Test public void test01() { bookService.buyBook("ISBN-001", "Tom"); } }
声明式事务的五大属性【拓展】
Propagation:传播机制:一个带有事务的方法A运行在另一个带有事务的方法B的内部的时候,内层方法A是使用自己的事务还是使用外层方法B的事务。 取值: required、requires_new、supports Required【默认值】:如果外层方法有事务,就用外层方法的事务.如果外层方法没有事务,内层方法就自己开一个新的事务。 requires_new: 无论外层方法有没有事务,内层方法都用自己的事务 Supports: 如果外层方法有事务,就用外层方法的事务.如果外层方法没有事务,内层方法就不用事务了。 Isolation: 隔离级别: 针对数据库的并发访问 Read_uncommited:读未提交 Read_commited:读已提交 Repeatable_read:[默认值]可重复读:在一个事务内多次读取的数据表的数据是一致的。 Serializable: 串行化读 这四个隔离级别,按着从上到下的顺序,并发度越来越低,但是安全性越来越高。 rollbackFor:回滚属性 事务默认只是在遇到RuntimeException才会回滚,如果遇到了编译时异常,默认是不会回滚的,如果想让编译时异常回滚,可以设置rollbackFor属性.
同理,对于运行时异常【RuntimeException】如果不想让它回滚,可以设置norollbackFor属性 Timeout: 超时属性 事务在运行过程中,势必会占用数据库的资源,如果一个事务长时间运行,就会导致数据库的资源长时间被占用,就会影响其它事务的执行,所以为了不让某个事务长时间占用数据库资源,我们可以为事务设置超时属性,当在规定的时间内,如果一个事务还没 有执行成功,就让该事务回滚。这个时间表示多次操作数据库之间的总时间.当多次操作数据库之间的总时间<timeout设置的时间时,执行成功,否则回滚 readOnly: 只读属性:加快访问速度 True: 在该方法中,就不能对数据库进行增删改操作。 False: 数据库的锁: 共享锁: 排它锁
Propagation:传播机制
当第二个事务里的数据有问题时,第二个事务回滚了,book表的数据不变
第一个事务正常执行了
rollbackFor:回滚属性
运行时异常
编译时异常
Timeout: 超时属性
休眠时间<超时时间时
休眠时间>超时时间时
org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Thu Dec 19 17:02:15 CST 2019
基于xml的声明式事务
把事务放进切面
SpringMVC的入门
在web.xml文件中配置springmvc的前端控制器
在web.xml文件中配置springmvc的前端控制器
创建springmvc的配置文件,并配置扫描包和内部资源视图解析器
<!-- 配置内部资源视图解析器 作用:将逻辑视图转换为物理视图,并转发到该视图 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
例子:
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="hello">寻找hello</a> </body> </html>
编写Control类
@Controller public class UserController { @RequestMapping("/hello") public String success() { return "aaa"; } }
WEB-INF/pages/aaa.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>这是aaa页面</h1>
</body>
</html>
问题1
/和/*的区别:
/拦截所有请求,不拦截jsp请求
/*拦截所有请求,包括jsp请求
原因:
处理*.jsp是tomcat做的事,所有项目的小web.xml都是继承大web.xml。DefaultServlet是处理除jsp和servlet外剩下的静态资源,服务器的大web.xml中有一个DefaultServlet是url-pattern=/
springMVC的配置前端控制器url-pattern=/ 。前端控制器中的/禁用了tomcat服务器中DefaultServle的/
那为什么jsp可以访问?
因为前端控制器中没有覆盖服务器中的jspServlet的配置
问题2
服务器的根目录:http://localhost:8080/ 项目的根目录:http://localhost:8080/springmvc01/ 相对路径:不是以/开头的路径是相对路径 绝对路径:以/开头的路径是绝对路径 /:到底代表服务器的根目录还是项目的根目录,取决于/是被浏览器端解析还是被服务器端解析 /被浏览器端解析,代表的是服务器的根目录: Response.sendRedirect(“/index.jsp”) 页面中:html、jsp中使用html标签中/ /被服务器端解析,代表的是项目的根目录 Request.getRequestDispatcher(“/”).forward() 后台配置文件中的/ Jsp中的jsp所特有的标签: <jsp:forward “/”>