jd - JiyangM/spring GitHub Wiki
几乎所有web应用容器都提供了四种类似Map的结构:application session request page,Jsp或者Servlet通过向着这四个对象放入数据,从而实现Jsp和Servlet之间数据的共享。
application:整个应用 对应servlet中ServletContext session:会话 对应servlet中HttpSession request:一次请求 对应servlet中的HttpServletRequest page:当前页面
---
### 如何防止SQL注入?
我们以登录账号为起始点。
通常,登录账号要求我们输入的是账号(userName)、密码(passWord)
输入完点击确定后后台这里用的java将产生一条sql语句。
假如我们用Java原声的产生sql语句方式,而不是用 PreparedStatement,代码是这样写的:
```java
String sql = "select * from table where user_name='" + userName +"' and pass_word='" + passWord + "'";
将会生成一条语句(这里加入我输入账号:zhanghao 密码:123)
select * from table where user_name ='zhanghao' and 'pass_word=123'
select * from table where user_name ='' or 1=1 #'and pass_word='123'
其中用户如果数据的参数值是' or 1=1 #' # 在mysql中表示注释,则该sql也会执行成功。
防止SQl注入手段
很多语言已经帮我们做好了对应的API。比如Java我们用PreparedStatement
String sql= "select * from users where username=? and password=?;
PreparedStatement preState = conn.prepareStatement(sql);
preState.setString(1, userName);
preState.setString(2, password);
ResultSet rs = preState.executeQuery();
PreparedStatement 防止sql注入的原理,会将参数中的单引号转义
String sql = "select * from goods where min_name = ?"; // 含有参数
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, "儿童'"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@d704f0: select * from goods where min_name = '儿童\''
上面的sql在执行的时候将会报错,从而防止了sql注入。
上面的是String参数防止sql注入的方式,对于整数类型,PreparedStatement 提供了 setInt setLong 的方式。
或者,我们可以用正则,把 有 单引号(‘),分号(;) 和 注释符号(–)的语句给替换掉来防止SQL注入
return str.replaceAll(".([';]+|(--)+).", " ");
PreparedStatement 百分之百的防止SQL注入吗?不是的对于用户输入的% PreparedStatement 是不会做转义处理,在模糊查询时将对数据有影响。
解决办法
悲观锁 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。 Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被block。 乐观锁 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。 乐观锁一般来说有以下2种方式:
使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。 使用时间戳(timestamp)。乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
innodb 可以通过两种方式实现行级锁定,即Shared(S) lock和Exclusive Lock (X)。以下简称为S锁和X锁。
S锁为共享锁,持有S锁的事务可以对该行进行读取操作,且其他session对该行不可修改。
X锁为排他锁,持有X锁的事务可以对该行进行修改操作。
如果一条记录被加了S锁,那么其他事务仍可以对其加S锁。 如果一条记录被加了X锁,那么其他事务不可以对其他加S锁或者X锁。
设置共享锁:SELECT ... LOCK IN SHARE MODE; 共享锁都是行锁 设置排他锁:SELECT ... FOR UPDATE; 排它锁可以使行锁也可以是表锁
mysql InnoDB引擎默认的修改数据语句 update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型
共享锁和意向共享锁,排他锁与意向排他锁的区别
共享锁和排他锁,系统在特定的条件下会自动添加共享锁或者排他锁,也可以手动添加共享锁或者排他锁。 意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预。
共享锁和排它锁,可能锁定的是表,也可能锁定的是行 例如
SELECT count(*) as total FROM test WHERE username = "mraz" FOR UPDATE
当username是主键时,锁定的是行锁, 当username不是主键时,是表锁
只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
什么是意向共享锁,什么是意向排他锁? 意向共享锁,简称IS,其作用在于:通知数据库接下来需要施加什么锁并对表加锁。如果需要对记录A加共享锁,那么此时innodb会先找到这张表,对该表加意向共享锁之后,再对记录A添加共享锁。 意向排他锁,简称IX,其作用在于:通知数据库接下来需要施加什么锁并对表加锁。如果需要对记录A加排他锁,那么此时innodb会先找到这张表,对该表加意向排他锁之后,再对记录A添加排他锁。 意向共享锁和意向排它锁是数据库主动加的,不需要我们手动处理
https://www.cnblogs.com/rainwang/p/4429211.html
可对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁(范围锁),保证新的满足查询条件的记录不会被插入。
SQL规范下的repeatable read允许出现幻读,但InnoDB依靠范围锁,在repeatable read级别下也可避免幻读。
是InnoDB的默认隔离级别。
使用乐观锁(MVCC),使用范围锁。
Java JUC中的atomic包就是乐观锁的一种实现,AtomicInteger 通过CAS(Compare And Set)操作实现线程安全的自增。 MySQL隐式和显示锁定 MySQL InnoDB采用的是两阶段锁定协议(two-phase locking protocol)。在事务执行过程中,随时都可以执行锁定,锁只有在执行 COMMIT或者ROLLBACK的时候才会释放,并且所有的锁是在同一时刻被释放。前面描述的锁定都是隐式锁定,InnoDB会根据事务隔离级别在需要的时候自动加锁。 另外,InnoDB也支持通过特定的语句进行显示锁定,这些语句不属于SQL规范:
SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE
- $("p[id]")
- $("#id")
客户端发送一条查询给服务器。
服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段。
服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划。
MySQL根据优化器生成的执行计划,再调用存储引擎的API来执行查询。
将结果返回给客户端。
find access_log.20160423.txt | xargs cat | grep .*helloworld.*|wc -l
find access_log.20160423.txt | xargs cat | grep -v .*helloworld.*|wc -l
public static int recursionBinarySearch(int[] arr,int key,int low,int high){
if(key < arr[low] || key > arr[high] || low > high){
return -1;
}
int middle = (low + high) / 2; //初始中间位置
if(arr[middle] > key){
//比关键字大则关键字在左区域
return recursionBinarySearch(arr, key, low, middle - 1);
}else if(arr[middle] < key){
//比关键字小则关键字在右区域
return recursionBinarySearch(arr, key, middle + 1, high);
}else {
return middle;
}
}
- 工厂模式
分为静态工厂、实例工厂
所谓静态工厂方式就是指Factory类不本身不需要实例化, 这个Factory类中提供了1个静态方法来生成bean对象。
java中调用线程池用的就是静态工厂,Executors 里面有很多的静态方法。
实例工厂的应用:
关键点:利用@Autowired,自动注入指定接口实现类到List中。不用自己写复杂的扫描类。
接口代码:
/**
* 获取用户信息的接口
* Created by daniel on 2017-05-08.
*/
public interface IUserInfoService {
/**
* 获取该实例支持的用户类型
* @return
*/
public String getSupportUserType();
/**
* 根据用户名和类型获取用户信息
* @param userName 用户名
* @param userType 用户类型
* @return 用户信息
*/
public UserInfo getUserInfo(String userName, String userType);
/**
* 根据userToken获取用户信息
* @param userToken
* @return
*/
public UserInfo getUserInfo(String userToken);
/**
* 获取用户具备的权限列表,用于权限判断
* @param userName
* @param userType
* @return
*/
public List<String> getUserPermissions(String userName, String userType);
}
Factory类,第4、5行即为关键代码,能将IUserInfoService的所有子类注入到List中。
public class UserInfoServiceFactory {
@Autowired
private List<IUserInfoService> iUserInfoServices;
public IUserInfoService getUserInfoService(String type) {
IUserInfoService userInfoService = null;
for (IUserInfoService tmpService : iUserInfoServices) {
if (tmpService.getSupportUserType().equals(type)) {
userInfoService = tmpService;
break;
}
}
return userInfoService;
}
}
- 单例模式
查询一下配置参数,程序运行的一些参数信息
- 观察者模式
做缓存,做一些辅助的操作
工厂模式是为了解耦:把对象的创建和使用的过程分开
-
事物的特性(ACID): 1.原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; 2.一致性: 执行事务前后,数据保持一致; 3.隔离性: 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的; 4.持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
-
事务管理 :按照给定的事务规则来执行提交或者回滚操作
Spring并不直接管理事务,而是提供了多种事务管理器。 Spring事务管理器的接口是: org.springframework.transaction.PlatformTransactionManager ,通过这个接口, Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
PlatformTransactionManager接口中定义了三个方法:
Public interface PlatformTransactionManager()...{
// Return a currently active transaction or create a new one, according to the specified propagation behavior(根据指定的传播行为,返回当前活动的事务或创建一个新事务。)
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// Commit the given transaction, with regard to its status(使用事务目前的状态提交事务)
Void commit(TransactionStatus status) throws TransactionException;
// Perform a rollback of the given transaction(对执行的事务进行回滚)
Void rollback(TransactionStatus status) throws TransactionException;
}
比如我们在使用JDBC或者iBatis(就是Mybatis)进行数据持久化操作时,我们的xml配置通常如下:
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务, 这个方法里面的参数是 TransactionDefinition类 ,这个类就定义了一些基本的事务属性。
public interface TransactionDefinition {
// 返回事务的传播行为
int getPropagationBehavior();
// 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
int getIsolationLevel();
// 返回事务必须在多少秒内完成
//返回事务的名字
String getName();
int getTimeout();
// 返回是否优化为只读事务。
boolean isReadOnly();
}
- 并发事务带来的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致一下的问题。
脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复度和幻读区别:
不可重复读的重点是修改,幻读的重点在于新增或者删除。
- 隔离级别
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:默认的隔离级别
- 事务传播行为(为了解决业务层方法之间互相调用的事务问题)
1、 TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
2、 TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
3、TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
-
事务只读属性(对事物资源是否执行只读操作) 事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源, 比如数据源、 JMS 资源,以及自定义的事务性资源等等。 如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。
-
回滚规则(定义事务回滚规则) 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
-
TransactionStatus接口介绍
TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息.
PlatformTransactionManager.getTransaction(…) 方法返回一个 TransactionStatus 对象。 返回的TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。
TransactionStatus接口接口内容如下:
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
索引失效:
- 最左前缀 abc 复合索引 缺少a 全表扫描 bc 使用a少别的效果差
- 不在索引列上做任何操作(计算,函数,(自动或者手动)类型装换),会导致索引失效而导致全表扫描
- mysql使用不等于(!= 或者<>)的时候,无法使用索引,会导致索引失效
- like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。
- or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效。
- 在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。
- 当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效。
HTTP 是一个属于应用层的面向对象的协议,HTTP 协议一共有五大特点:
1、支持客户/服务器模式
4、无连接;5、无状态。
- 无连接
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
大部分通道实际上会很空闲、无端占用资源。因此 HTTP 的设计者有意利用这种特点将协议设计为请求时建连接、请求完释放连接, 以尽快将资源释放出来服务其他客户端。
随着时间的推移,网页变得越来越复杂,里面可能嵌入了很多图片,这时候每次访问图片都需要建立一次 TCP 连接就显得很低效。后来,Keep-Alive 被提出用来解决这效率低的问题。
Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。市场上的大部分 Web 服务器,包括 iPlanet、IIS 和 Apache,都支持 HTTP Keep-Alive。对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站来说,这里存在另外一个问题:虽然为客户保留打开的连接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep-Alive 功能对资源利用的影响尤其突出。
这样一来,客户端和服务器之间的 HTTP 连接就会被保持,不会断开(超过 Keep-Alive 规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接。
- 无状态
无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。
即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息。
HTTP 协议这种特性有优点也有缺点,优点在于解放了服务器,每一次请求“点到为止”不会造成不必要连接占用,缺点在于每次请求会传输大量重复的内容信息。
客户端与服务器进行动态交互的 Web 应用程序出现之后,HTTP 无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session。
Cookie可以保持登录信息到用户下次与服务器的会话,换句话说,下次访问同一网站时,用户会发现不必输入用户名和密码就已经登录了(当然,不排除用户手工删除Cookie)。而还有一些Cookie在用户退出会话的时候就被删除了,这样可以有效保护个人隐私。
Cookies 最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是 Cookies 的功用。另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入 Cookies,以便在最后付款时提取信息。
与 Cookie 相对的一个解决方案是 Session,它是通过服务器来保持状态的。
当客户端访问服务器时,服务器根据需求设置 Session,将会话信息保存在服务器上,同时将标示 Session 的 SessionId 传递给客户端浏览器,浏览器将这个 SessionId 保存在内存中,我们称之为无过期时间的 Cookie。浏览器关闭后,这个 Cookie 就会被清掉,它不会存在于用户的 Cookie 临时文件。
以后浏览器每次请求都会额外加上这个参数值,服务器会根据这个 SessionId,就能取得客户端的数据信息。
如果客户端浏览器意外关闭,服务器保存的 Session 数据不是立即释放,此时数据还会存在,只要我们知道那个 SessionId,就可以继续通过请求获得此 Session 的信息,因为此时后台的 Session 还存在,当然我们可以设置一个 Session 超时时间,一旦超过规定时间没有客户端请求时,服务器就会清除对应 SessionId 的 Session 信息。
要说http就绕不开tcp,TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性。但是,http是基于tcp协议的。
Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。 Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。 所以Http连接是一种短连接,是一种无状态的连接。 所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接。
如果是一个连接的话,服务器进程中就能保持住这个连接并且在内存中记住一些信息状态。而每次请求结束后,连接就关闭,相关的内容就释放了,所以记不住任何状态,成为无状态连接。
- TCP三次握手和四次挥手?
被问烂了的问题了,这里不详细讲了,三次握手:
客户端–发送带有SYN标志的数据包–一次握手–服务端 服务端–发送带有SYN/ACK标志的数据包–二次握手–客户端 客户端–发送带有带有ACK标志的数据包–三次握手–服务端
TCP(Transmission Control Protocol)传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。
### 为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
### 香香
https://juejin.im/post/5a0444d45188255ea95b66bc
所谓HTTP协议的无状态性是指服务器的协议层无需为不同的请求之间建立任何相关关系,它特指的是协议层的无状态性。但是这并不代表建立在HTTP协议之上的应用程序就无法维持状态。 应用层可以通过会话Session来跟踪用户请求之间的相关性,服务器会为每个会话对象绑定一个唯一的会话ID,浏览器可以将会话ID记录在本地缓存LocalStorage或者Cookie,在后续的请求都带上这个会话ID,服务器就可以为每个请求找到相应的会话状态。
- 输入地址浏览器查找域名的 IP 地址,这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存...
- 浏览器向 web 服务器发送一个 HTTP 请求
- 服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
- 浏览器跟踪重定向地址
- 服务器处理请求
- 服务器返回一个 HTTP 响应
- 浏览器显示 HTML
- 浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
- 浏览器发送异步请求
进程类
- top top -Hp
文本类
- grep -v
- awk
- sed
其他
- ls
- cd
- mkdir
- rm
- echo
- tar
- md5
- find / -name "hadooop*"
- history
- ssh-keygen
- 修饰变量 String
- 修饰方法,该方法不能被子类重写
- 修饰类,表示该类是完整的,不能被继承
参考 https://www.jianshu.com/p/f68d6ef2dcf0
使用Redis集成Spring Session
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
}
Hessian(基于HTTP的远程方法调用)基于HTTP协议传输。HessianProxyFactoryBean。
dubbo.
生命周期:
当服务器启动时,web应用加载后,立即创建这个web应用中的所有的过滤器,过滤器创建出来后立即调用init方法执行初始化的操作.
创建出来后一直驻留在内存中为后续的拦截进行服务.每次拦截到请求后都会导致doFilter方法执行.
在服务器关闭或web应用被移除出容器时,随着web应用的销毁过滤器对象销毁.销毁之前调用destory方法执行善后工作.
当哈希表的哈希因子达到一定阈值的时候,为了减小冲突率,需要进行Rehash操作。 Redis的Rehash机制是这样,首先创建新的哈希表,其次进行数据迁移。 因为整体数据迁移是及其耗时的操作,Redis将数据迁移操作散列在每次数据请求处理中,比如前端请求key,如果发现key在老的哈希表中,会将它迁移到新的哈希表中。
从结构上看每个字典中都包含了两个hashtable。 那么为什么一个字典会需要两个hashtable? 首先redis在正常读写时会用到一个hashtable,而另一个hashtable的作用实际上是作为字典在进行rehash时的一个临时载体。 我们可以这么理解,redis开始只会用一个hashtable去读写,如果这个hashtable的数据量增加或者缩减到某个值,到达了rehash的条件,redis便会开始根据数据量和链(bucket)的个数初始化那个备用的hashtable,来使这个hashtable从容量上满足后续的使用,并开始把之前的hashtable的数据迁移到这个新的hashtable上来,当然这种迁移是对每个节点值进行一次hash运算。等到数据全部迁移完成,再进行一次hashtable的地址更名,把这个备用的hashtable为正式的hashtable,同时清空另一个hashtable以供下一次rehash使用。
https://blog.csdn.net/heyongluoyao8/article/details/51413668
- 分布式事务 使用分布式锁
- session spring session
https://blog.csdn.net/CSDN_Terence/article/details/77744042
很多人认为方法区(或者HotSpot虚拟机中的永久代)是没有垃圾收集的,Java虚拟机规范中确实说过可以不要求虚拟机在方法区实现垃圾收集,而且在方法区中进行垃圾收集
的“性价比”一般比较低:在堆中,尤其是在新生代中,常规应用进行一次垃圾收集一般可以回收70%~95%的空间,而永久代的垃圾收集效率远低于此。
永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。回收废弃常量与回收
Java堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串“abc”已经进入了常量池中,但是当前系统没有任何一个String对象是叫做“abc”的,换句话说,就是没有任何
String对象引用常量池中的“abc”常量,也没有其他地方引用了这个字面量,如果这时发生内存回收,而且必要的话,这个“abc”常量就会被系统清理出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。
判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是“无用的类”:
该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。加载该类的ClassLoader已经被回收。