打个广告,帮朋友卖点东西,东西超便宜的哟【衣服鞋子等】,厂家直接出货,绝对低于市场价!!! 一般都比市场价便宜3—7折【都是牌子货】,如果您感兴趣,可以扫描屏幕下方的二维码,感谢关注!!!
一、JdbcTemplate
spring 提供的用于操作JDBC工具类,类似:DBUtils。依赖 连接池DataSource (数据源)
1、环境搭建
1.创建表
create database ee19_spring_day02;
use ee19_spring_day02;
create table t_user(
id int primary key auto_increment,
username varchar(50),
password varchar(32)
);
insert into t_user(username,password) values('jack','1234');
insert into t_user(username,password) values('rose','5678');
2.创建bean
public class User {
private Integer id;
private String username;
private String password;
//get set
}
2、入门演示
public class TestApi {
public static void main(String[] args) {
//1 创建数据源(连接池) dbcp
BasicDataSource dataSource = new BasicDataSource();
// * 基本4项
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/ee19_spring_day02");
dataSource.setUsername("root");
dataSource.setPassword("1234");
//2 创建模板
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//3 通过api操作
jdbcTemplate.update("insert into t_user(username,password) values(?,?);", "tom","998");
}
}
说明:执行该部分代码即可向数据库中添加数据
3、配置数据库连接池
开发中数据库连接池在spring配置文件中进行配置,这里新建一个dao用来封装数据库操作:
public class UserDao {
//jdbc模板将由spring注入
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
//更新操作
public void update(User user){
String sql = "update t_user set username=?,password=? where id =?";
Object[] args = {user.getUsername(),user.getPassword(),user.getId()};
jdbcTemplate.update(sql, args);
}
// 查询所有
public List<User> findAll() {
return jdbcTemplate.query("select * from t_user", ParameterizedBeanPropertyRowMapper.newInstance(User.class));
}
//根据id查询
public User getById(int id) {
return this.getJdbcTemplate().queryForObject("select * from t_user where id = ?", ParameterizedBeanPropertyRowMapper.newInstance(User.class), id);
}
}
说明:ParameterizedBeanPropertyRowMapper.newInstance(User.class)用来将查询数据结果封装到bean中。
1.配置DBCP连接池
<!-- 创建数据源 -->
<bean id="dataSourceId" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/ee19_spring_day02"></property>
<property name="username" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!-- 创建模板 ,需要注入数据源-->
<bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceId"></property>
</bean>
<!-- 配置dao -->
<bean id="userDaoId" class="com.itheima.c_dbcp.UserDao">
<property name="jdbcTemplate" ref="jdbcTemplateId"></property>
</bean>
那么它的测试类如下:
public class TestDBCP {
@Test
public void demo01(){
User user = new User();
user.setId(1);
user.setUsername("接客");
user.setPassword("998");
String xmlPath = "com/itheima/c_dbcp/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//获得目标类
UserDao userDao = (UserDao) applicationContext.getBean("userDaoId");
userDao.update(user);
}
}
2.配置c3p0连接池
需要更改的部分只有创建数据源部分:
<!-- 创建数据源 c3p0-->
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day02"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>
那么它的测试类如下:
@Test
public void demo01(){
String xmlPath = "com/itheima/d_c3p0/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserDao userDao = (UserDao) applicationContext.getBean("userDaoId");//获得目标类
List<User> allUser = userDao.findAll();
for (User user : allUser) {
System.out.println(user);
}
}
4、精减优化
1.使用JdbcDaoSupport
在Dao中每次都要自己创建jdbcTemplate模板,比较繁琐,可以将Dao继承JdbcDaoSupport:
public class UserDao extends JdbcDaoSupport{
public void update(User user){
String sql = "update t_user set username=?,password=? where id =?";
Object[] args = {user.getUsername(),user.getPassword(),user.getId()};
this.getJdbcTemplate().update(sql, args);//直接调用父类的
}
//。。。。
}
在配置文件中也可以简化:
<!-- 创建数据源 c3p0-->
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--不变-->
</bean>
<!-- 配置dao 只需要注入数据源,底层将自动创建模板-->
<bean id="userDaoId" class="com.itheima.e_jdbcdaosupport.UserDao">
<property name="dataSource" ref="dataSourceId"></property>
</bean>
2.使用properties文件
可以将数据库配置信息放在properties文件(jdbcInfo.properties)中:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ee19_spring_day02
jdbc.user=root
jdbc.password=1234
配置文件更改为:
<!-- 加载配置文件
"classpath:"前缀表示 src下
在配置文件之后通过 ${key} 获得内容
-->
<context:property-placeholder location="classpath:com/itheima/f_properties/jdbcInfo.properties"/>
<!-- 创建数据源 c3p0-->
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
二、事务管理
1、与事务相关的接口
1.PlatformTransactionManager
平台事务管理器,spring要管理事务,必须使用事务管理器(进行事务配置时,必须配置事务管理器)。事务管理器是通过“事务详情”,获得“事务状态”,从而管理事务。
常见的事务管理器有(即其实现类):
- DataSourceTransactionManager ,jdbc开发时事务管理器,采用JdbcTemplate
- HibernateTransactionManager,hibernate开发时事务管理器,整合hibernate
2.TransactionDefinition
事务详情(又称事务定义、事务属性),spring用于确定事务具体详情(例如:隔离级别、是否只读、超时时间 等)。进行事务配置时,必须配置详情。spring将配置项封装到该对象实例。
其中的方法有:
getPropagationBehavior() | 传播行为 |
getIsolationLevel() | 隔离级别 |
getTimeout() | 获取超时时间 |
isReadOnly() | 是否只读(增删改 读写,查 只读) |
getName | 配置事务详情名称。一般方法名称。例如:save |
其中的常量有:
- 默认超时时间:
TIMEOUT_DEFAULT:默认值为-1,代表的是使用数据库底层的超时时间
- 事务的隔离级别(分别为:0、1、2、4、8):
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITED
ISOLATION_READ_COMMITED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
- 传播行为(即在两个业务之间如何共享事务):
PROPAGATION_REQUIRED :required , 必须 【默认值】
=》支持当前事务,A如果有事务,B将使用该事务。
=》如果A没有事务,B将创建一个新的事务。
PROPAGATION_SUPPORTS :supports ,支持
=》支持当前事务,A如果有事务,B将使用该事务。
=》如果A没有事务,B将以非事务执行。
PROPAGATION_MANDATORY,mandatory ,强制
=》支持当前事务,A如果有事务,B将使用该事务。
=》如果A没有事务,B将抛异常。
PROPAGATION_REQUIRES_NEW , requires_new ,必须新的
=》如果A有事务,将A的事务挂起,B创建一个新的事务
=》如果A没有事务,B创建一个新的事务
PROPAGATION_NOT_SUPPORTED ,not_supported ,不支持
=》如果A有事务,将A的事务挂起,B将以非事务执行
=》如果A没有事务,B将以非事务执行
PROPAGATION_NEVER ,never,从不
=》如果A有事务,B将抛异常
=》如果A没有事务,B将以非事务执行
PROPAGATION_NESTED ,nested ,嵌套
=》A和B底层采用保存点机制,形成嵌套事务。
掌握:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
3.TransactionStatus
事务状态,spring用于记录当前事务运行状态(例如:是否有保存点,事务是否完成)。spring底层根据状态进行相应操作。其方法有:
isNewTransaction() | 是否是新事务 |
hasSavepoint() | 是否有保存点 |
setRollbackOnly() | 设置回滚 |
isRollbackOnly() | 是否回滚 |
flush() | 刷新 |
isCompleted() | 是否完成 |
2、具体实现
1.搭建环境
以银行转账为例,首先创建表如下:
create database ee19_spring_day03;
use ee19_spring_day03;
create table account(
id int primary key auto_increment,
username varchar(50),
money int
);
insert into account(username,money) values('jack','10000');
insert into account(username,money) values('rose','10000');
之后dao层为:
public interface AccountDao {
public void out(String outer , Integer money);//汇款
public void in(String inner , Integer money);// 收款
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
public void out(String outer, Integer money) {
this.getJdbcTemplate().update("update account set money = money - ? where username = ?", money,outer);
}
public void in(String inner, Integer money) {
this.getJdbcTemplate().update("update account set money = money + ? where username = ?", money,inner);
}
}
service层则为:
public interface AccountService {
public void transfer(String outer ,String inner ,Integer money);//转账
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//转账实现
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
// int i = 1/0;//断电
accountDao.in(inner, money);
}
}
而在spring中的配置:
<!-- 1 datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!-- 2 dao -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3 service -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
在测试类中:
@Test
public void demo01(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.transfer("jack", "rose", 1000);
}
运行如上代码转账成功,现在开始在上述代码中添加事务操作。
2.手动管理事务
spring底层使用 TransactionTemplate 事务模板进行操作。因此可以自己通过TransactionTemplate来进行管理事务具体步骤如下:
1.service 需要获得 TransactionTemplate,那么service代码修改为:
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//需要spring注入模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public void transfer(final String outer,final String inner,final Integer money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {//事务放在这里
accountDao.out(outer, money);
// int i = 1/0;//断电
accountDao.in(inner, money);
}
});
}
}
2.在spring配置文件中需要配置模板,并注入给service,模板需要注入事务管理器,配置事务管理器(需要注入DataSource)那么在xml配置文件中新加:
<!-- 4 创建模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"></property>
</bean>
<!-- 5 配置事务管理器 ,管理器需要事务,事务从Connection获得,连接从连接池DataSource获得 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
即可完成事务添加
3.工厂bean 生成代理(半自动)
spring提供一个管理事务的代理工厂bean TransactionProxyFactoryBean。那么在配置文件中配置其代理工厂(之前不变):
<!-- 4 service 代理对象 -->
<bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces" value="com.itheima.service.AccountService"></property>
<property name="target" ref="accountService"></property>
<property name="transactionManager" ref="txManager"></property>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
</props>
</property>
</bean>
<!-- 5 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
说明:在使用代理工厂时:
- transactionManager 事务管理器
- transactionAttributes 事务属性(事务详情)
prop.key :确定哪些方法使用当前事务配置
prop.text:用于配置事务详情
格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
传播行为 隔离级别 是否只读 异常回滚 异常提交
例如:
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> 默认传播行为,和隔离级别
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> 只读
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.ArithmeticException</prop> 有异常扔提交
之后再测试类中获取的是代理对象,而不是原对象:
@Test
public void demo01(){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = (AccountService) applicationContext.getBean("proxyAccountService");
accountService.transfer("jack", "rose", 1000);
}
4.AOP 配置基于xml
在spring 配置文件中配置aop 自动生成代理,进行事务的管理。
<!-- 4 事务管理 -->
<!-- 4.1 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 4.2 事务详情(事务通知) , 在aop筛选基础上,对ABC三个确定使用什么样的事务。例如:AC读写、B只读 等-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--用于配置事务详情(属性属性)-->
<tx:attributes>
<!--propagation 传播行为 ;isolation 隔离级别-->
<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!-- 4.3 AOP编程,目标类有ABCD(4个连接点),切入点表达式 确定增强的连接器,从而获得切入点:ABC -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service..*.*(..))"/>
</aop:config>
5.AOP配置基于注解
采用注解方式需要在spring配置中添加新的命名空间,及配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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.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
http://www.springframework.org/schema/tx <!--这里-->
http://www.springframework.org/schema/tx/spring-tx.xsd"><!--这里-->
<!--之前-->
<!-- 4 事务管理 -->
<!-- 4.1 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 4.2 将管理器交予spring
* transaction-manager 配置事务管理器
* proxy-target-class(true : 底层强制使用cglib 代理)
-->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
之后在目标类或目标方法添加注解即可 @Transactional
@Transactional()
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
int i = 1/0;//断电
accountDao.in(inner, money);
}
}
注意:之前的事务详情怎么配,在@Transactional中添加参数即可,如:
@Transactional(propagation=Propagation.REQUIRED , isolation = Isolation.DEFAULT)