裸泳的猪

沾沾自喜其实最可悲

0%

spring事务管理

Spring定义了7种传播行为:

  1. propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,
    加入到这个事务中,这是Spring默认的选择。
  2. propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
  3. propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
  4. propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
  5. propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
  7. propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

Spring事务隔离级别

Spring事务隔离级别比数据库事务隔离级别多一个default

1) DEFAULT (默认)
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。

2) READ_UNCOMMITTED (读未提交)
这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

3) READ_COMMITTED (读已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

4) REPEATABLE_READ (可重复读)
这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

5) SERIALIZABLE(串行化)
这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

事务几种实现方式

  1. 编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
  2. 基于 TransactionProxyFactoryBean的声明式事务管理
  3. 基于 @Transactional 的声明式事务管理
  4. 基于Aspectj AOP配置事务

基于 TransactionProxyFactoryBean的声明式事务管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- 事务管理器 -->

<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 事务代理工厂 -->
<!-- 生成事务代理对象 -->
<bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="myTracnsactionManager"></property>
<property name="target" ref="buyStockService"></property>
<property name="transactionAttributes">
<props>
<!-- 主要 key 是方法
ISOLATION_DEFAULT 事务的隔离级别
PROPAGATION_REQUIRED 传播行为
-->
<prop key="add*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
<!-- -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
<prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-BuyStockException</prop>
</props>
</property>

</bean>

基于 @Transactional 注解的声明式事务管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class BuyStockServiceImpl implements BuyStockService{

private AccountDao accountDao;
private StockDao stockDao;

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
@Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money);

}

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
@Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount);

}

public BuyStockServiceImpl() {
// TODO Auto-generated constructor stub
}

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=BuyStockException.class)
@Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy);

}

public AccountDao getAccountDao() {
return accountDao;
}

public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

public StockDao getStockDao() {
return stockDao;
}

public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
}

}

配置文件:

1
2
3
4
5
6
7
<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="myTracnsactionManager"/>

基于Aspectj AOP配置事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<context:property-placeholder location="classpath:jdbc.properties"/>

<!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></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="accountDao" class="transaction.test4.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="stockDao" class="transaction.test4.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="buyStockService" class="transaction.test4.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean>


<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

<tx:advice id="txAdvice" transaction-manager="myTracnsactionManager">
<tx:attributes>
<!-- 为连接点指定事务属性 -->
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="BuyStockException"/>
</tx:attributes>
</tx:advice>

<aop:config>
<!-- 切入点配置 -->
<aop:pointcut expression="execution(* *..service.*.*(..))" id="point"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>

原文地址:https://www.cnblogs.com/h-c-g/p/10872061.html

Sentinel

主要概念相关

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。


st

Sentinel 基本概念

资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

规则

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

使用

基本使用 - 资源与规则

集成apollo


针对来源进行限流

1.首先我们要自定义来源解析RequestOriginParser

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class SentinelConfig {
@Bean
public RequestOriginParser requestOriginParser() {
return (request -> {
String remoteAddr = IpUtils.getRemoteAddr(request);
return remoteAddr;
});
}

}

2.接下来我们设置来源 ,填入限制的ip,

ip

3.即可实现针对ip的限流

Eureka Server:注册中心服务端

注册中心服务端主要对外提供了三个功能:

  • 服务注册
    服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表
  • 提供注册表
    服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表
    • 注册表的数据结构:registry的CocurrentHashMap,就是注册表的核心结构。同时维护注册表、拉取注册表、更新心跳时间,全部发生在内存里!这是Eureka Server非常核心的一个点。
  • 同步状态

高可用原理

其实每一个服务端(这里指实例)都内置了一个Eureka Client,也就是说一个服务端可以接受其他Client的注册,也可以作为一个Client注册到其他Server上,被其他Client发现和调用。一个服务端实例你可以理解为由一个Server+Client组成。

Eureka

Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点

如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。

另外 Eureka Server 的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。所以,如果存在多个节点,只需要将节点之间两两连接起来形成通路,那么其它注册中心都可以共享信息。每个 Eureka Server 同时也是 Eureka Client,多个 Eureka Server 之间通过 P2P 的方式完成服务注册表的同步。

Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的。

Eureka 保证 AP,优先保证可用性,牺牲了一定的一致性。相对的zookeeper则是保证了CP,牺牲了部分的可用性。

JVM的定义

JVM(Java Virtual Machine,Java虚拟机)。

JVM是JAVA实现跨平台的主要手段,事实上jvm是有较多的实现版本,各种系统下的JVM不同。

由于jvm是处在Java语言和操作系统之间的,所以它要向上提供对Java的支持,向下与操作系统良好交互。

jvm

JVM中的数据结构

主要分为基本类型引用类型

阅读全文 »

在高并发的网络应用中,保护系统的稳定性和可用性是至关重要的。

缓存、熔断、降级、限流

缓存的目的是为了降低系统的访问延迟,提高系统能力,给用户更好的体验
熔断的目的是为了在发现某个服务故障熔断对下游依赖的请求,减少不必要的损耗
降级的目的是为了在系统在某个环节故障(比如某个下游故障)不影响整体核心链路,比如返回作者列表,关注服务故障了获取不了关注真实的关注情况,这种情况可以考虑降级关注按钮,全部显示为未关注
限流的目的是为了保证系统处理的请求量在可以承受的范围内,防止突发流量压垮系统,保证系统稳定性。

目标:限定请求量在系统可承受范围内。

阅读全文 »

模糊匹配like %%怎么优化

  1. 开启ICP(索引条件下推)
  • 索引下推(index condition pushdown )简称ICP,在Mysql5.6的版本上推出,用于优化查询。
  • 在使用ICP的情况下,如果存在某些被索引的列的判断条件时,MySQL服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合MySQL服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器 。
  • 索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少MySQL服务器从存储引擎接收数据的次数。****

可以通过索引筛选,返回给Server层筛选后的记录,减少不必要的IO开销。

如果where后只有一个 like ‘%xxx%’条件,表有主键的前提下,可以通过子查询优化

1
2
3
select  * from users01 a , 
(select id from users01 where nickname like '%SK%') b
where a.id = b.id;
  1. 建立全文索引

    两种检索模式
  • MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引;

  • MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引;

  • 只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。

  • IN NATURAL LANGUAGE MODE:默认模式,以自然语言的方式搜索,AGAINST(‘看风’ IN NATURAL LANGUAGE MODE ) 等价于AGAINST(‘看风’)。

  • IN BOOLEAN MODE:布尔模式,表是字符串前后的字符有特殊含义,如查找包含SK,但不包含Lyn的记录,可以用+,-符号。
    AGAINST(‘+SK -Lyn’ in BOOLEAN MODE);

创建全文索引:

1
alter table users01 add fulltext index idx_full_nickname(nickname) with parser ngram;

改写like语句:

1
select * from users01 where match(nickname) against('看风');
  1. 生成列(虚拟列)

    对于where条件后的 like ‘%xxx’ 是无法利用索引扫描,可以利用MySQL 5.7的生成列模拟函数索引的方式解决,具体步骤如下:
    利用内置reverse函数将like ‘%风云’反转为like ‘云风%’,基于此函数添加虚拟生成列。
    在虚拟生成列上创建索引。
    将SQL改写成通过生成列like reverse(‘%风云’)去过滤,走生成列上的索引。
    建立生成列
    1
    alter table users01 add reverse_nickname varchar(200) generated always as (reverse(nickname));

索引很长的字段怎么优化?

有时候需要索引很长的字符(例如BLOB,TEXT,或者很长的VARCHAR),这样会使得索引又大又慢。

  1. 改用哈希索引
    InnoDB是支持Btree索引,但不显式支持hash索引。可以使用生成列来间接使用哈希索引
  2. 使用字符串的前几个字符作为索引(即前缀索引)。
1
2
3
ALTER TABLE `city_demo` ADD INDEX `idx_city` (`city`(7)) USING BTREE ;
-- 或者这个也行
ALTER TABLE `city_demo` ADD KEY `idx_city` (`city`(7))

当然在选择前缀时要选择合适的前缀索引长度,保持好的选择性。其方法主要是计算数据分布。

1
2
3
4
5
6
-- 查询重复次数最多的10条完整城市名称及其数量(图1)
SELECT COUNT(*) cnt, city FROM city_demo GROUP BY city ORDER BY cnt DESC LIMIT 10;
-- 查询重复次数最多的10条城市名称(前3个字符)及其数量,可以发现:前3个字符的相同数量过大,不适合做前缀索引(图2)
SELECT COUNT(*) cnt, LEFT(city,3) pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;
-- 查询重复次数最多的10条城市名称(前7个字符)及其数量,可以发现:前7个字符的相同数量和完整城市名称很相近了,可以考虑作为做前缀索引(图3)
SELECT COUNT(*) cnt, LEFT(city,7) pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;

MRR

MRR全称是Multi-Range Read,是MYSQL5.6优化器的一个新特性,在MariaDB5.5也有这个特性。优化的功能在使用二级索引做范围扫描的过程中减少磁盘随机IO和减少主键索引的访问次数。二级索引通过将主键放在buffer中排序将随机IO转换为顺序IO。对于随机读写能力较弱的机械硬盘有比较大优化。

设计模式的六大原则

  • 单一职责原则

    一个类只负责一个功能领域的相应职责

    实现高内聚,低耦合的指导方针

  • 开闭原则

    对扩展开放,对修改关闭

  • 里氏替换原则LSP

  • 依赖倒转原则

  • 接口隔离原则

  • 迪米特法则

    • 最少知道原则,一个实体类应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对对立

    • 类之间的耦合度越低,就越有利用于复用

设计模式的三大设计模式分类

  • 创建型

    1
    2
    常用:工厂模式,抽象工厂模式,单例模式,建造者模式
    不常用:原型模式
  • 结构型

    1
    2
    常用:适配器、桥接、装饰器、代理
    不常用:组合、外观、享元
  • 行为型

    1
    2
    常用: 观察者模式、模板模式、策略模式、责任链模式、迭代器模式、状态模式。
    不常用: 访问者模式、备忘录模式、命令模式、解释器模式、中介模式。

入门问题

1.请列举出在 JDK 中几个常用的设计模式?

单例模式(Singleton pattern)用于 Runtime,Calendar 和其他的一些类中。工厂模式
(Factory pattern)被用于各种不可变的类如 Boolean,像 Boolean.valueOf,观察者模式
(Observer pattern)被用于 Swing 和很多的事件监听中。装饰器设计模式(Decorator
design pattern)被用于多个 Java IO 类中。

2.什么是设计模式?你是否在你的代码里面使用过任何设计模式?

设计模式是世界上各种各样程序员用来解决特定设计问题的尝试和测试的方法。设计模式
是代码可用性的延伸。

模板方法模式定义一个操作中的算法的骨架,将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。

应用场景如下:

对于一些功能,在不同的对象身上展示不同的作用,但是功能的框架是一样的。

3.Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

单例模式重点在于在整个系统上共享一些创建时较耗资源的对象。整个应用中只维护一个
特定类实例,它被所有组件共同使用。Java.lang.Runtime 是单例模式的经典例子。从 Java
5 开始你可以使用枚举(enum)来实现线程安全的单例。

阅读全文 »

适配器模式(Adapter Pattern)

  • 见名知意,是作为两个不兼容的接⼝之间的桥梁,属于结构型模式

  • 适配器模式使得原本由于接⼝不兼容⽽不能⼀起⼯作的 那些类可以⼀起⼯作

  • 常⻅见的⼏类适配器

    • 类的适配器模式
      • 想将⼀个类转换成满⾜另⼀个新接⼝的类时,可 以使⽤类的适配器模式,创建⼀个新类,继承原 有的类,实现新的接⼝即可
      • 对象的适配器模式
        • 想将⼀个对象转换成满⾜另⼀个新接⼝的对象 时,可以创建⼀个适配器类,持有原类的⼀个实 例,在适配器类的⽅法中,调⽤实例的⽅法就⾏
      • 接⼝的适配器模式
        • 不想实现⼀个接⼝中所有的⽅法时,可以创建⼀ 个Adapter,实现所有⽅法,在写别的类的时 候,继承Adapter类即

总结

  • 在使⽤⼀些旧系统或者是类库时,经常会出现接⼝不兼 容的问题,适配器模式在解决这类问题具有优势

  • 学习设计模式⼀定不要局限代码层⾯,要从软件系统整 体去考虑,⽽不是为了使⽤设计模式,⽽去使⽤设计模式

优点

  • 可以让任何两个没有关联的类⼀起运⾏,使得原本由于 接⼝不兼容⽽不能⼀起⼯作的那些类可以⼀起⼯作 增加灵活度, 提⾼复⽤性,适配器类可以在多个系统使 ⽤,符合开闭原则

缺点

整体类的调⽤链路增加,本来A可以直接调⽤C,使⽤适 配器后 是A调⽤B,B再调⽤C

mysql的4大特性+4种隔离级别:

4大特性即ACID

  • 1 原子性。事务是一个不可分割的整体,事务开始的操作,要么全部执行,要么全部不执行。
  • 2 隔离性。同一时间,只允许一个事务请求同一组数据。不同的事务彼此之间没有干扰。
  • 3 一致性。事务开始前和结束后,数据库的完整性约束没有被破坏 。
  • 4 稳定性。事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

4种隔离级别

大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read

阅读全文 »

  1. #{}和${}的区别是什么?
  • #{}是预编译处理#{}可以防止Sql 注入,它会将所有传入的参数作为一个字符串来处理。
  • ${}是字符串替换。${} 则将传入的参数拼接到Sql上去执行,一般用于表名和字段名参数,$ 所对应的参数应该由服务器端提供,前端可以用参数进行选择,避免 Sql 注入的风险
    Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
    Mybatis在处理时,就是把{}替换成变量的值。

    使用#{}可以有效的防止SQL注入,提高系统安全性。
  1. Mybatis是如何进行分页的?分页插件的原理是什么?

    Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

    分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
阅读全文 »