当前位置: 首页 > news >正文

Spring3~~~

目录

多例

后置处理器BeanPostProcessor

XML配置

 通过注解

AOP与后置处理器

JdbcTemplate

 jdbc.properties

jdbc.xml

Test

具名参数

DAO 

声明式事务

GoodsDao

GoodsService

xml 

传播机制

种类

隔离级别

超时回滚


如果是普通的java项目,xml文件放在src下
如果是java maven项目,xml文件放在resources下

多例

默认情况下,@Component、@Controller、@Service、@Repository是单例的

在Sping1~~~文章中讲解了xml配置单例和多例

@Component
@Scope(value = "prototype")
public class UserAction {}

后置处理器BeanPostProcessor

XML配置

作用在该容器创建的Bean对象

<bean class="spring.bean.MyBeanPostProcessor" id="myBeanPostProcessor"/>

 通过注解

作为一个组件注入到容器中,所以在xml中需要扫描到它才会作用

@Component
public class Process implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

指定init()是初始化方法 
即使不指定初始化方法,后置处理器也会调用postProcessBeforeInitialization

@Component
public class UserService {@PostConstructpublic void init() {}
}

AOP与后置处理器

AOP实现Spring可以给类加上注解:@EnableAspectJAutoProxy

@Component
@EnableAspectJAutoProxy
public class UserDao {}

对Dog进行切面,后置处理器初始化和销毁返回的对象不一样,初始化后切面,变成代理对象

JdbcTemplate

是Spring提供的访问数据库的技术,可以将JDBC的常用操作封装为模板方法

前面的名字可以自己设置

 jdbc.properties

user=root
pwd=123456
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis

jdbc.xml

使用c3p0

    <!--引入外部的jdbc.properties文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置数据源对象-DataSoruce--><bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource"><!--给数据源对象配置属性值--><property name="user" value="${user}"/><property name="password" value="${pwd}"/><property name="driverClass" value="${driver}"/><property name="jdbcUrl" value="${url}"/></bean><!--配置JdbcTemplate对象--><bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate"><!--给JdbcTemplate对象配置dataSource--><property name="dataSource" ref="dataSource"/></bean>

可以通过id获取,也可以通过接口获取

Test

    @Testpublic void t1() throws SQLException {ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc.xml");//通过id获取//DataSource dataSource = (DataSource)ioc.getBean("dataSource");//通过接口获取DataSource dataSource = ioc.getBean(DataSource.class);Connection connection = dataSource.getConnection();connection.close();System.out.println(connection);}//测试通过JdbcTemplate对象完成添加数据@Testpublic void addDataByJdbcTemplate() {//获取到容器ApplicationContext ioc =new ClassPathXmlApplicationContext("jdbc.xml");//获取JdbcTemplate对象JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);//1. 添加方式1//String sql = "INSERT INTO monster VALUES(400, '红孩儿', '枪法')";//jdbcTemplate.execute(sql);//2. 添加方式2String sql = "INSERT INTO monster VALUES(?, ?, ?)";//affected表示 执行后表受影响的记录数int affected = jdbcTemplate.update(sql, 500, "红孩儿2", "枪法2");System.out.println("add ok affected=" + affected);}//测试通过JdbcTemplate对象完成修改数据@Testpublic void updateDataByJdbcTemplate() {//获取到容器ApplicationContext ioc =new ClassPathXmlApplicationContext("jdbc.xml");//获取JdbcTemplate对象JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);//组织SQLString sql = "UPDATE monster SET skill=? WHERE id=?";int affected = jdbcTemplate.update(sql, "美女计", 300);System.out.println("update ok affected= " + affected);}//批量添加二个monster 白蛇精和青蛇精//这里有一个使用API的技巧/*** 1. 对于某个类, 有很多API, 使用的步骤* 2. 使用技巧(1) 先确定API名字 (2) 根据API提供相应的参数 [组织参数]*    (3) 把自己的调用思路清晰 (4) 根据API, 可以推测类似的用法和功能* batch add data* 批量添加二个monster 白蛇精和青蛇精-update(sql,List<Object[]>)*/@Testpublic void addBatchDataByJdbcTemplate() {ApplicationContext ioc = new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");//得到JdbcTemplate beanJdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);//添加..//1. 先确定,猜测API名称 batchUpdate//public int[] batchUpdate(String sql, List<Object[]> batchArgs){}//2. 准备参数String sql = "INSERT INTO monster VALUES(?, ?, ?)";List<Object[]> batchArgs = new ArrayList<>();batchArgs.add(new Object[]{600, "老鼠精", "偷吃粮食"});batchArgs.add(new Object[]{700, "老猫精", "抓老鼠"});//3. 调用//说明:返回结果是一个数组,每个元素对应上面的sql语句对表的影响记录数int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);//输出for (int anInt : ints) {System.out.println("anInt=" + anInt);}System.out.println("batch add ok..");}//查询id=100的monster并封装到Monster实体对象[在实际开发中,非常有用]@Testpublic void selectDataByJdbcTemplate() {ApplicationContext ioc = new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");//得到JdbcTemplate beanJdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);//组织SQL//通过BeanPropertyRowMapper获取rowmapper 是一个接口,可以将查询的结果,封装到你指定的Monster对象中.//1. 确定API : queryForObject()//public <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)//2.准备参数String sql = "SELECT id AS monsterId, NAME, skill FROM monster WHERE id = 100";//使用RowMapper 接口来对返回的数据,进行一个封装-》底层使用的反射->setter//这里有一个细节: 你查询的记录的表的字段需要和 Monster的对象字段名保持一致RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);//jdbcTemplateMonster monster = jdbcTemplate.queryForObject(sql, rowMapper);System.out.println("monster= " + monster);System.out.println("查询ok");}//查询id>=200的monster并封装到Monster实体对象/*** 查询多条记录*/@Testpublic void selectMulDataByJdbcTemplate() {ApplicationContext ioc =new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");//得到JdbcTemplate beanJdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);//组织SQL//通过BeanPropertyRowMapper获取rowmapper 是一个接口,可以将查询的结果,封装到你指定的Monster对象中.//1.    确定API//public <T> T query(String sql, RowMapper<T> rowMapper, Object... args){}//2. 组织参数String sql = "SELECT id AS monsterId, NAME, skill FROM monster WHERE id >= ?";RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);//3. 调用List<Monster> monsterList = jdbcTemplate.query(sql, rowMapper, 100);for (Monster monster : monsterList) {System.out.println("monster= " + monster);}}/*** 查询返回结果只有一行一列的值*/@Testpublic void selectScalarByJdbcTemplate() {ApplicationContext ioc =new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");//得到JdbcTemplate beanJdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);//1. 确定API//public <T> T queryForObject(String sql, Class<T> requiredType)//2. 提供参数String sql = "SELECT NAME FROM monster WHERE id = 100";//Class<T> requiredType 表示你返回的单行单列的数据类型String name =jdbcTemplate.queryForObject(sql, String.class);System.out.println("返回name= " + name);}

具名参数

xml配置NamedParameterJdbcTemplate对象

    <!--配置NamedParameterJdbcTemplate对象--><bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"id="namedParameterJdbcTemplate"><!--通过构造器,设置数据源--><constructor-arg name="dataSource" ref="dataSource"/></bean>
    /*** 使用Map传入具名参数完成操作,比如添加*/@Testpublic void testDataByNamedParameterJdbcTemplate() {ApplicationContext ioc =new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");//得到NamedParameterJdbcTemplate beanNamedParameterJdbcTemplate namedParameterJdbcTemplate =ioc.getBean(NamedParameterJdbcTemplate.class);//1. 确定使用API//public int update(String sql, Map<String, ?> paramMap)//2. 准备参数 [:my_id, :name, :skill] 要求按照规定的名字来设置参数String sql = "INSERT INTO monster VALUES(:id, :name, :skill)";Map<String, Object> paramMap = new HashMap<>();//给paramMap填写数据paramMap.put("id", 800);paramMap.put("name", "蚂蚁精");paramMap.put("skill", "喜欢打洞");//3. 调用int affected = namedParameterJdbcTemplate.update(sql, paramMap);System.out.println("add ok affected=" + affected);}//使用sqlparametersoruce 来封装具名参数,还是添加一个Monster 狐狸精@Testpublic void operDataBySqlparametersoruce() {ApplicationContext ioc =new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");//得到NamedParameterJdbcTemplate beanNamedParameterJdbcTemplate namedParameterJdbcTemplate =ioc.getBean(NamedParameterJdbcTemplate.class);//确定API//public int update(String sql, SqlParameterSource paramSource)//public BeanPropertySqlParameterSource(Object object)//准备参数,用对象来传递,应该是对象的属性名String sql = "INSERT INTO monster VALUES(:monsterId, :name, :skill)";Monster monster = new Monster(900, "大象精", "搬运木头");SqlParameterSource sqlParameterSource =new BeanPropertySqlParameterSource(monster);//调用int affected =namedParameterJdbcTemplate.update(sql, sqlParameterSource);System.out.println("add ok affected= " + affected);}

DAO 

xml添加扫描包路径

@Repository //将MonsterDao 注入到spring容器
public class MonsterDao {//注入一个属性@Resourceprivate JdbcTemplate jdbcTemplate;//完成保存任务public void save(Monster monster) {//组织sqlString sql = "INSERT INTO monster VALUES(?,?,?)";int affected = jdbcTemplate.update(sql, monster.getMonsterId(), monster.getName(), monster.getSkill());System.out.println("affected= " + affected);}
}//测试MonsterDAO@Testpublic void monsterDaoSave() {ApplicationContext ioc =new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");MonsterDao monsterDao = ioc.getBean(MonsterDao.class);Monster monster = new Monster(1000, "小鸭精", "吃鱼");monsterDao.save(monster);System.out.println("MonsterDAO保存 ok ..");}

声明式事务

传统

声明式事务将每个步骤写成一个方法
各个方法搭配可以组成一个新事务

GoodsDao

@Repository //将 GoodsDao-对象 注入到spring容器
public class GoodsDao {@Resourceprivate JdbcTemplate jdbcTemplate;//根据商品id,返回对应的价格public Float queryPriceById(Integer id) {String sql = "SELECT price From goods Where goods_id=?";Float price = jdbcTemplate.queryForObject(sql, Float.class, id);return price;}//修改用户的余额 [减少用户余额]public void updateBalance(Integer user_id, Float money) {String sql = "UPDATE user_account SET money=money-? Where user_id=?";jdbcTemplate.update(sql, money, user_id);}//修改商品库存 [减少]public void updateAmount(Integer goods_id, int amount){String sql = "UPDATE goods_amount SET goods_num=goods_num-? Where goods_id=?";jdbcTemplate.update(sql, amount , goods_id);}//根据商品id,返回对应的价格public Float queryPriceById2(Integer id) {String sql = "SELECT price From goods Where goods_id=?";Float price = jdbcTemplate.queryForObject(sql, Float.class, id);return price;}//修改用户的余额 [减少用户余额]public void updateBalance2(Integer user_id, Float money) {String sql = "UPDATE user_account SET money=money-? Where user_id=?";jdbcTemplate.update(sql, money, user_id);}//修改商品库存 [减少]public void updateAmount2(Integer goods_id, int amount){String sql = "UPDATE goods_amount SET goods_num=goods_num-? Where goods_id=?";jdbcTemplate.update(sql, amount , goods_id);}
}

GoodsService

    /*** @Transactional 注解解读* 1. 使用@Transactional 可以进行声明式事务控制* 2. 即将标识的方法中的,对数据库的操作作为一个事务管理* 3. @Transactional 底层使用的仍然是AOP机制* 4. 底层是使用动态代理对象来调用buyGoodsByTx* 5. 在执行buyGoodsByTx() 方法 先调用 事务管理器的 doBegin() , 调用 buyGoodsByTx()* 如果执行没有发生异常,则调用 事务管理器的 doCommit(), 如果发生异常 调用事务管理器的 doRollback()*/@Transactionalpublic void buyGoodsByTx(int userId, int goodsId, int amount) {//1.得到商品的价格Float price = goodsDao.queryPriceById(userId);//2. 减少用户的余额goodsDao.updateBalance(userId, price * amount);//3. 减少库存量goodsDao.updateAmount(goodsId, amount);System.out.println("用户购买成功~");}

xml 

    <!--1. DataSourceTransactionManager 这个对象是进行事务管理-debug源码2. 一定要配置数据源属性,这样指定该事务管理器 是对哪个数据源进行事务控制--><bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"><property name="dataSource" ref="dataSource"/></bean><!--配置启动基于注解的声明式事务管理功能--><tx:annotation-driven transaction-manager="transactionManager"/>

传播机制

种类

重点:前两种

REQUIRES_NEW是独立的,不受外面的事务影响,如果失败只会回滚当前的事务

REQUIRE是一个整体,只要错误,都不会执行成功

 

 隔离级别

修改隔离级别 

 @Transactional(isolation = Isolation.READ_COMMITTED)

超时回滚

超过2s回滚

http://www.lryc.cn/news/436848.html

相关文章:

  • 微服务CI/CD实践(五)Jenkins Docker 自动化构建部署Java微服务
  • 泰州高新区法院多层面强化固定资产管理
  • JDBC简介与应用:Java数据库连接的核心概念和技术
  • 倒反天罡!这个AI风格模型可自由训练,还能批量生成同风格图像
  • Stable Diffusion绘画 | ControlNet应用-Inpaint(局部重绘):更完美的重绘
  • 电网谐波越限怎么处理
  • Redis中的AOF重写过程及其实际应用
  • JVM面试
  • 【模板的特殊继承关系】 奇异的递归模板模式
  • SAP B1 单据页面自定义 - 用户界面编辑字段
  • MinIO【部署 02】Linux集群版本及Windows单机版、单机多目录版、分布式版(cmd启动脚本及winsw脚本分享)
  • 手握18个大厂offer,我在大模型风口起飞
  • 邦芒忠告:办公室聊天应避开的四个话题
  • 交易型开放式指数基金(ETF)
  • opencv将灰度图转为彩色图片
  • 判断PDF与图片是否可以预览
  • 多线程与并发区别
  • 这个桌面日历真不错 笔记 提醒 生日记录 打卡 翻译都有 真的太方便了!
  • 多模态大语言模型综述(中)-算法实用指南
  • Qt | ubuntu20.04安装Qt6.5.3并创建一个example完整教程(涉及诸多开发细节,商用慎重)
  • 苏州科技大学、和数联合获得国家知识产权局颁发的3项发明专利证书
  • CleanMyMac X2024破解版mac电脑清理工具
  • 微软数据库的SQL注入漏洞解析——Microsoft Access、SQLServer与SQL注入防御
  • 无人机之处理器篇
  • 828华为云征文 | 华为云Flexus X实例上实现Docker容器的实时监控与可视化分析
  • 缓存预热/雪崩/穿透/击穿
  • C/C++:优选算法
  • 用于大数据分析的数据存储格式:Parquet、Avro 和 ORC 的性能和成本影响
  • 【Jupyter Notebook】安装与使用
  • 默认端口被占用后,如何修改Apache2 端口