spring整合jdbc
spring中提供了一个可以操作数据库的对象(JDBCTemplate),对象封装了jdbc技术。
1.使用spring整合jdbc需要jdbc驱动、c3p0连接池、spring-jdbc、spring-tx事务包。
2.准备数据库
CREATE TABLE `david2018_db`.`UserInfo` ( `Id` INT NOT NULL AUTO_INCREMENT, `UserName` VARCHAR(255) NULL, PRIMARY KEY (`Id`));
3.src下新建配置文件c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!--默认配置--> <default-config> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> </default-config> <!--配置连接池mysql--> <named-config name="mysql"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/david2018_db</property> <property name="user">root</property> <property name="password">1234</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> </named-config> </c3p0-config>
4.编写测试类
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); ComboPooledDataSource dataSource=new ComboPooledDataSource("mysql"); //创建jdbc模板对象 JdbcTemplate jt = new JdbcTemplate(); //注入连接池 jt.setDataSource(dataSource); //添加 jt.update("insert into userinfo (userName) values ('david')"); //修改 jt.update("update userinfo set username = 'tom' where id = 1"); }
5.与spring整合 新建UserInfo实体类,IUserInfoDao接口,UserInfoDaoImpl实现类
package com.david.bean; public class UserInfo { private Integer Id; private String UserName; public Integer getId() { return Id; } public void setId(Integer id) { Id = id; } public String getUserName() { return UserName; } public void setUserName(String userName) { UserName = userName; } }
package com.david.dao; import com.david.bean.UserInfo; import java.util.List; public interface IUserInfoDao { void save(UserInfo u); void update(UserInfo u); void delete(UserInfo u); UserInfo getUserById(Integer id); int getTotalCount(); List<UserInfo> getUserList(); }
package com.david.dao; import com.david.bean.UserInfo; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; public class UserInfoDaoImpl implements IUserInfoDao{ //定义一个jdbc模板等着spring注入 private JdbcTemplate jt; public JdbcTemplate getJt() { return jt; } public void setJt(JdbcTemplate jt) { this.jt = jt; } @Override public void save(UserInfo u) { String sql = "insert into userinfo (username) values (?)"; jt.update(sql,u.getUserName()); } @Override public void update(UserInfo u) { String sql = "update userinfo set username = ? where id = ?"; jt.update(sql,u.getUserName(),u.getId()); } @Override public void delete(UserInfo u) { String sql = "delete from userinfo where id = ?"; jt.update(sql,u.getId()); } @Override public UserInfo getUserById(Integer id) { String sql = "select * from userinfo where id = ?"; return jt.queryForObject(sql, new RowMapper<UserInfo>() { @Override public UserInfo mapRow(ResultSet rs, int rowNum) throws SQLException { UserInfo u = new UserInfo(); u.setId(rs.getInt("id")); u.setUserName(rs.getString("username")); return u; } },id); } @Override public int getTotalCount() { String sql = "select count(*) from userinfo"; return jt.queryForObject(sql,Integer.class); } @Override public List<UserInfo> getUserList() { String sql = "select * from userinfo"; return jt.query(sql, new RowMapper<UserInfo>() { @Override public UserInfo mapRow(ResultSet rs, int rowNum) throws SQLException { UserInfo u = new UserInfo(); u.setId(rs.getInt("id")); u.setUserName(rs.getString("username")); return u; } }); } }
6.将Dao配置到spring容器 不需要用c3p0-config.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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!--将连接池放入spring容器 --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property> <property name="user" value="root"></property> <property name="password" value="1234"></property> </bean> <!--将JDBCTemplate放入spring容器 --> <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--将UserInfoDao放入spring容器 --> <bean name="userInfoDao" class="com.david.dao.UserInfoDaoImpl"> <property name="jt" ref="jdbcTemplate"></property> </bean> </beans>
7.测试
public class Main { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserInfoDaoImpl userInfoDao = (UserInfoDaoImpl) ac.getBean("userInfoDao"); //添加 UserInfo u = new UserInfo(); u.setUserName("salinna"); userInfoDao.save(u); //修改 UserInfo u1 = new UserInfo(); u1.setId(1); u1.setUserName("black"); userInfoDao.update(u1); //删除 UserInfo u2 = new UserInfo(); u2.setId(2); userInfoDao.delete(u2); //查询数量 int totalCount = userInfoDao.getTotalCount(); System.out.println(totalCount); //查询单个user UserInfo u3 = userInfoDao.getUserById(1); System.out.println(u3); //查询user列表 List<UserInfo> userList = userInfoDao.getUserList(); for(UserInfo u4 : userList){ System.out.println(u4); } } }
spring中aop事务
spring中封装了事务管理代码:事务操作(打开事务、提交事务、回滚事务),因为在不同平台操作事务的代码各不相同,所以spring提供了一个接口PlatformTransactionManger该接口实现类有DataSourceTransactionManager,HibernateTransactionManager等。
spring管理事务的属性
1.事务的隔离性:1248选择哪个隔离级别级别
2.是否只读:如果打开 本次操作不允许修改数据库中的数据
3.事务传播行为:解决业务方法之间调用,事务应该如何处理
3.1:TransactionDefinition.PROPAGATION_REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
3.2:TransactionDefinition.PROPAGATION_REQUIRES_NEW 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
3.3:TransactionDefinition.PROPAGATION_SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
3.4:TransactionDefinition.PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
3.5:TransactionDefinition.PROPAGATION_NEVER 以非事务方式运行,如果当前存在事务,则抛出异常。
3.6:TransactionDefinition.PROPAGATION_MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
3.7:TransactionDefinition.PROPAGATION_NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
创建数据表
CREATE TABLE `david2018_db`.`Account` ( `Id` INT NOT NULL AUTO_INCREMENT, `UserName` VARCHAR(45) NULL, `Money` DOUBLE NULL, PRIMARY KEY (`Id`));
测试数据
insert into account (username,money) values ('david',1000);
insert into account (username,money) values ('jack',1000);
创建接口、实现类
package com.david.dao; public interface IAccountDao { void addMoney(Integer id,Double money); void decreaseModeny(Integer id,Double money); }
package com.david.dao; import org.springframework.jdbc.core.support.JdbcDaoSupport; //继承JdbcDaoSupport 这个类就可以直接使用jdbctemplate对象了 不用定义属性 然后去注入了 public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao { @Override public void addMoney(Integer id, Double money) { getJdbcTemplate().update("update account set money = money + ? where id = ?",money,id); } @Override public void decreaseModeny(Integer id, Double money) { getJdbcTemplate().update("update account set money = money - ? where id = ?",money,id); } }
编写服务类
package com.david.service; public interface IAccountService { void transfer(Integer from,Integer to,Double money); }
package com.david.service; import com.david.dao.IAccountDao; public class AccountServiceImpl implements IAccountService { private IAccountDao ad; @Override public void transfer(Integer from, Integer to, Double money) { //减钱 ad.decreaseModeny(from, money); //加钱 ad.addMoney(to, money); } public IAccountDao getAd() { return ad; } public void setAd(IAccountDao ad) { this.ad = ad; } }
编写配置文件注入
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property> <property name="user" value="root"></property> <property name="password" value="1234"></property> </bean> <bean name="accountDao" class="com.david.dao.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean name="accountService" class="com.david.service.AccountServiceImpl"> <property name="ad" ref="accountDao"></property> </bean> </beans>
编写测试代码
public class Main { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountServiceImpl accountService = (AccountServiceImpl) ac.getBean("accountService"); accountService.transfer(1,2,100D); } }
现在是没有事务的,如果在减少钱后 发生异常 此时 钱没了, 对方还没收到.
public void transfer(Integer from, Integer to, Double money) { //减钱 ad.decreaseModeny(from, money); int i = 1 / 0; //加钱 ad.addMoney(to, money); }
spring三种加入事务的方式:
1.编码式(了解):
<!--事务核心管理器,封装了所有事务操作。依赖连接池 --> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 编码式需要模板对象,依赖事务核心管理器 --> <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> </beans>
在AccountService中定义一个transactionTemplate属性并生成get set方法
public class AccountServiceImpl implements IAccountService { private IAccountDao ad; private TransactionTemplate tt; ...
在spring容器中 注入transactionTemplate
<bean name="accountService" class="com.david.service.AccountServiceImpl"> <property name="ad" ref="accountDao"></property> <property name="tt" ref="transactionTemplate"></property> </bean>
编写事务代码-无需手写打开事务 提交事务
public class AccountServiceImpl implements IAccountService { private IAccountDao ad; private TransactionTemplate tt; @Override public void transfer(Integer from, Integer to, Double money) { tt.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { //减钱 ad.decreaseModeny(from, money); int i = 1 / 0; //加钱 ad.addMoney(to, money); } }); } ...
2.xml配置(aop):
导入aop包和依赖包,导入aop命名空间,配置通知,织入
<?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.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property> <property name="user" value="root"></property> <property name="password" value="1234"></property> </bean> <bean name="accountDao" class="com.david.dao.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean name="accountService" class="com.david.service.AccountServiceImpl"> <property name="ad" ref="accountDao"></property> </bean> <!--事务核心管理器,封装了所有事务操作。依赖连接池 --> <bean name="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="transfer" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <!--配置多个方法:通配符匹配 以什么开头的所有方法 --> <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="persist*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="modify*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="remove*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/> </tx:attributes> </tx:advice> <!--配置织入 --> <aop:config> <!--切入点 --> <aop:pointcut id="txPc" expression="execution(* com.david.service.AccountServiceImpl.*(..))"></aop:pointcut> <!--配置切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"></aop:advisor> </aop:config> </beans>
3.注解配置(aop):
使用注解也是要导包,命名空间,然后开启注解
<?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.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/david2018_db"></property> <property name="user" value="root"></property> <property name="password" value="1234"></property> </bean> <bean name="accountDao" class="com.david.dao.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean name="accountService" class="com.david.service.AccountServiceImpl"> <property name="ad" ref="accountDao"></property> </bean> <!--事务核心管理器,封装了所有事务操作。依赖连接池 --> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启注解事务 --> <tx:annotation-driven></tx:annotation-driven> </beans>
然后再service实现类使用Transactional注解
@Override @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false) public void transfer(Integer from, Integer to, Double money) { //减钱 ad.decreaseModeny(from, money); //加钱 ad.addMoney(to, money); }
也可以将注解加到类上 ,表示类中所有方法都开启事务。 优先级:方法上有先找方法的,方法没有才找类上的。