暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring入门(三)

浊酒独醉 2021-06-19
137
点击蓝字·关注我们


1. Spring JdbcTemplate

1.1 概述

JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。

1.2  JdbcTemplate基本使用

①导入spring-jdbc和spring-tx坐标

②创建数据库表和实体

③创建JdbcTemplate对象

④执行数据库操作


导入坐标

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>

创建数据库实体



创建对象,然后执行操作

public class SpringJDBCTest {


@Test
public void jdbctest() throws Exception {
// 创建数据源
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springlearn?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8");
dataSource.setUser("root");
dataSource.setPassword("root");


JdbcTemplate jdbcTemplate = new JdbcTemplate();
// 设置数据源,知道数据库在哪
jdbcTemplate.setDataSource(dataSource);
// 执行操作
int update = jdbcTemplate.update("insert into Person values (?,?,?)", "zhangsan", 18, "dongguan");
}
}


1.3  JdbcTemplate基本使用-Spring管控


将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模版对象中,然后通过Spring容器获得JdbcTemplate对象来执行操作。


配置spring管控JdbcTemplate和DataSource

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写-->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearn?useSSL=false&amp;serverTimezone=UTC&amp;characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>


<!-- 创建JDBC模板对象-->
<bean id="JDBCTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>


编码测试代码

//    Spring管理和创建JDBCTemplate对象
@Test
public void jdbctest1(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) app.getBean("JDBCTemplate");
int update = jdbcTemplate.update("insert into Person values (?,?,?)", "lisi", 18, "guanzhou");
System.out.println(update);
}


将填写内容抽取

<!--加载配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--创建数据源-->
<bean id="dataProPSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写-->
<!-- 用${}来取加载进配置文件的值-->
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>


<!-- 创建JDBC模板对象-->
<bean id="JDBCTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataProPSource" ref="dataProPSource"></property>
</bean>


其他数据库操作

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringJDBCTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void jdbctestcud(){
int insert = jdbcTemplate.update("insert into Person values (?,?,?)", "wangwu", 18, "guizhou");


int delet = jdbcTemplate.update("delete from Person where name =?", "lisi");


int update = jdbcTemplate.update("update Person set age =? where name =?", 30,"wangwu");


}
//查询全部
@Test
public void jdbctestqall(){
List<Person> person = jdbcTemplate.query(("select * from Person"), new BeanPropertyRowMapper<Person>(Person.class));
System.out.println(person);
}
//单条查询
@Test
public void jdbctestqone(){
Person person = jdbcTemplate.queryForObject(("select * from Person where name =?"), new BeanPropertyRowMapper<Person>(Person.class), "zhangsan");
System.out.println(person);
}
// 聚合查询
@Test
public void jdbctestqcount(){
Integer count = jdbcTemplate.queryForObject(("select count(*) from Person"), Integer.class);
System.out.println(count);
}


}


2. 声明式事务控制

编程式事务控制相关对象介绍:

2.1 PlatformTransactionManager

PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。

注意:

PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类。


例如:

Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager

Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager


2.2 TransactionDefinition

TransactionDefinition 是事务的定义信息对象,具体常用方法如下。

2.2.1 事务隔离级别

设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。


  • ISOLATION_DEFAULT

  • ISOLATION_READ_UNCOMMITTED

  • ISOLATION_READ_COMMITTED

  • ISOLATION_REPEATABLE_READ

  • ISOLATION_SERIALIZABLE


2.2.2  事务传播行为


  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)

  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)**

  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常

  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。

  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常

  • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作

  • 超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置

  • 是否只读:建议查询时设置为只读


2.3 TransactionStatus

TransactionStatus 接口提供的是事务具体的运行状态,方法如下。


3. 声明式事务控制

3.1 什么是声明式事务控制


Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。


声明式事务处理的作用:

  • 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可

  • 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便


注意:Spring 声明式事务控制底层就是AOP。


3.2 基于 XML 的声明式事务控制实现

声明式事务控制明确事项:

  • 谁是切点?

  • 谁是通知?

  • 配置切面?


dao层

//接口
public interface ShopDao {
public void out(String outname,double prices);
public void in(String inname,double prices);
}


//实现类


public class ShopDaoImpl implements ShopDao {


private JdbcTemplate jdbcTemplate;


public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}


public void out(String outname, double prices) {
jdbcTemplate.update("update shop set prices =prices-? where name =?",prices,outname);
}


public void in(String inname, double prices) {
jdbcTemplate.update("update shop set prices =prices+? where name =?",prices,inname);
}
}


service层

//接口
public interface ShopService {
public void transfer(String inname,String outname,double prices);
}


//实现类
public class ShopServiceImpl implements ShopService {
private ShopDao shopDao;


public void setShopDao(ShopDao shopDao) {
this.shopDao = shopDao;
}


public void transfer(String inname, String outname, double prices) {
// 开启事务
shopDao.in(inname,prices);
int i =1/0; //自定义错误 测试事务控制
shopDao.out(outname,prices);
// 提交事务
}
}


配置文件让Spring容器管控

<?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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">


<!--加载配置文件-->
<!-- <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>-->


<!-- <bean id="dataProPSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">-->
<!-- &lt;!&ndash; 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写&ndash;&gt;-->
<!--&lt;!&ndash; 用${}来取加载进配置文件的值&ndash;&gt;-->
<!-- <property name="driverClass" value="${jdbc.driver}"></property>-->
<!-- <property name="jdbcUrl" value="${jdbc.url}"></property>-->
<!-- <property name="user" value="${jdbc.username}"></property>-->
<!-- <property name="password" value="${jdbc.password}"></property>-->
<!-- </bean>-->


<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写-->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearn?useSSL=false&amp;serverTimezone=UTC&amp;characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>


<!-- 创建JDBC模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>


<!-- 配置ShopDao-->
<bean id="shopDao" class="com.joyfullyone.dao.impl.ShopDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>


<!-- 配置ShopService-->
<bean id="shopService" class="com.joyfullyone.service.impl.ShopServiceImpl">
<property name="shopDao" ref="shopDao"></property>
</bean>


<!-- 告诉spring使用哪种平台技术-->
<bean id="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="*"/>
</tx:attributes>
</tx:advice>


<!-- 配置事务aop织入-->
<aop:config>
<!-- 事务增强使用advisor-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.joyfullyone.service.impl.*.*(..))"></aop:advisor>
</aop:config>


</beans>


测试

public class ShopController {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
ShopService shopService = (ShopService) app.getBean("shopService");
shopService.transfer("lisi","zhangsan",10);
}
}


3.2.1 切点方法的事务参数的配置

具体参数可以看上一小点的具体属性

<!--    配置通知 也就是增强类  事务的增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 设置事务的属性-->
<tx:attributes>
<!-- 设置哪些方法增强事务
name 就是需要事务增强的方法名称(切点方法名称)
isolation:事务的隔离级别
propogation:事务的传播行为
timeout:超时时间
read-only:是否只读
-->
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/>
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/>
<tx:method name="*" />
</tx:attributes>
</tx:advice>

3.3 基于注解的声明式事务控制实现

配置包扫描和开启事务

<!--组件扫描-->
<context:component-scan base-package="com.joyfullyone"/>
<!-- 告诉spring使用哪种平台技术-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 参数的name 跟类的set方法对应 也就是set方法命名然后去掉set首字母小写-->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearn?useSSL=false&amp;serverTimezone=UTC&amp;characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>


<!-- 创建JDBC模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>

dao层用注解实现

//接口
public interface ShopDao {
public void out(String outname,double prices);
public void in(String inname,double prices);
}


//实现
@Repository("shopDao")
public class ShopDaoImpl implements ShopDao {


@Autowired
private JdbcTemplate jdbcTemplate;


public void out(String outname, double prices) {
jdbcTemplate.update("update shop set prices =prices-? where name =?",prices,outname);
}


public void in(String inname, double prices) {
jdbcTemplate.update("update shop set prices =prices+? where name =?",prices,inname);
}
}


service层注解实现

//接口
public interface ShopService {
public void transfer(String inname,String outname,double prices);
}


//实现
@Service("shopService")
public class ShopServiceImpl implements ShopService {
@Autowired
private ShopDao shopDao;


// public void setShopDao(ShopDao shopDao) {
// this.shopDao = shopDao;
// }
@Transactional
public void transfer(String inname, String outname, double prices) {
// 开启事务
shopDao.in(inname,prices);
int i =1/0;
shopDao.out(outname,prices);
// 提交事务
}
}


3.3.1 注解配置声明式事务控制解析

①使用 @Transactional 在需要进行事务控制的类或是方法上修饰,注解可用的属性同 xml 配置方式,例如隔离级别、传播行为等。

②注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。

③使用在方法上,不同的方法可以采用不同的事务参数配置。

④Xml配置文件中要开启事务的注解驱动<tx:annotation-driven />



END



文章转载自浊酒独醉,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论