水浅

  • Home

  • Tags14

  • Categories10

  • Search

Cglib代理

Posted on 2021-03-16 | In java基础
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
//被代理类
public class PersonService {
public void eat(){
System.out.println("吃饭");
}
}

//代理类
public class Cglib implements MethodInterceptor{

private Enhancer enhancer = new Enhancer();

public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("拿筷子" + method);
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("洗碗" + method);
return invoke;
}
}
//main
public class Main {

public static void main(String[] args) {
Cglib ct = new Cglib();
PersonService proxy = (PersonService) ct.getProxy(PersonService.class);
proxy.eat();
}
}

JDK 动态代理

Posted on 2021-03-16 | In java基础
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
//接口
public interface Subject {
void doSomeThink();
}

//实现类
public class RealSubject implements Subject{

@Override
public void doSomeThink() {
System.out.println("Do some thing");
}
}
//代理实现类
/**
* @author devin
* @version 1.0.2
* @date 2021-03-16 15:49
*/
public class JDKProxy implements InvocationHandler {
private Object target;
public JDKProxy(Object target) {
this.target = target;
}
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do some thing before");
Object result = method.invoke(target,args);
System.out.println("do some thing after");
return result;
}
}

// main 类
public class Main {
public static void main(String[] args) {
Subject subject = new JDKProxy(new RealSubject()).getProxy();
subject.doSomeThink();
}
}
  1. 如何实现流程

    1. 为接口创建代理类的字节码文件
    2. 将字节码文件加载到JVM
    3. 创建代理类实例对象,执行目标的方法
  2. proxy实现了哪些工作

    1. 代理类继承了Proxy类并且实现了要代理的接口,由于java不支持多继承,所以JDK动态代理不能代理类
    2. 重写了equals、hashCode、toString
    3. 有一个静态代码块,通过反射或者代理类的所有方法
    4. 通过invoke执行代理类中的目标方法doSomething

​

java编程思想

Posted on 2021-03-15 | Edited on 2021-03-16 | In 读书笔记

第二章

2.1 用引用来创建一个对象

1
2
3
//一切都是对象可以把引用作为一个遥控,例如 
string a; //只是定义了遥控没有定义遥控的对象
string a = "123" 才是OK 的

2.2 所有对象必须由你创建

1
2
3
4
5
6
7
8
string s = new String("1234");
/*
1. 寄存器访问最快的 位于CPU内部 但是数量有限 它是按需分配的 你不能感觉到它的存在
2. 堆栈:位于通用RAM 仅次于寄存器 向下则分配内存 向上则释放内存 java系统需要知道堆栈中所有项的生命 周期
3. 堆; 位于RAM 存储所有的java 对象 编译器不需要知道数据再堆中存活多长时间
4. 常量存储: 可以存储再程序代码内部也可以存储再只读存储器中
5. 非ram 存储: 两个基本的例子就是持久化和流对象
*/
  • 基本数据类型

    image-20210315032744369

    BigInteger BigDecimal

第五章

1
垃圾回收器准备垃圾回收之前先调用finalized 方法 并在下一次垃圾回收回收占用的内存

第八章

1
构造方法其实是静态方法  不过这种静态是隐性的

C++常用算法总结

Posted on 2021-03-13 | In 算法

PS:后续添加 没有顺序了 搜到什么看什么吧

非char型数组的复制

1
2
3
4
5
6
7
8
9
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[] = {1,2,3};
int b[3];
memcpy(b,a,2*sizeof(int));
cout << b[0] << b[1] << b[2] << endl;
}

查找子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s1 = "123";
string s2 = "23";
string s3 = "73";
cout << s1.find(s2) << endl;;
unsigned int c = s1.find(s3);
cout << c << endl;

// 如果没找到 发挥特别的指针 npos
// freopen("in.txt","r",stdin);
}

数据初始化

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
#include<bits/stdc++.h>
using namespace std;
#define MAXN 220
void display(int num)
{
cout << num << " ";
}
int main()
{
int a[2][5],b[10];
//fill只能初始化一维数组
fill(b,b+10,1);
//fill(a,a+100,1);
memset(a,0,sizeof(a));
//for_each(a,a+MAXN,display);

//数据输出
cout << "b:" << ":";
for_each(b,b+10,display);
cout << endl;

// cout << a << ":";
// for_each(a,a+10,display);
// cout << endl;
}

最大公约数

1
2
3
4
5
6
7
8
9
//公倍数 两数相乘  除以公约数
#include<bits/stdc++.h>
using namespace std;
int a[40] = {1,2};
int main()
{
cout << __gcd(12,6);
//cout << __INT32_MAX__ << endl;
}

1.accumulate求和

1
2
3
4
5
6
7
8
9
10
11
12
#include<numeric>
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(3);
v.push_back(5);
v.push_back(9);
cout << accumulate(v.begin(),v.end(),0); //0是累加的初值
}

2. atof 字符串转换为double

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
字符串 类型换成double类型
*/
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
int main()
{
char a[] = "123" ;
int b = atof(a);
cout << b;
}

3. 容器为空 begin和end相等

1
2
3
4
5
6
7
8
9
10
11
12
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v;
if(v.begin()==v.end())
cout << "ok1" << endl;
v.push_back(4);
if(v.begin()==v.end())
cout << "ok2" << endl;
}

4. bitset

可实现十进制和二进制的互换

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
#include<iostream>
#include<bitset>
using namespace std;
int main()
{
bitset<32> a(8);
cout << a[1] << endl;
int b;
b = a.to_ullong();
cout <<a << " " << b <<endl;
}
​```c
### 5.copy
​```c
/*
copy(begin,end,begin)
将第一个数组的begin至end 赋值到第二个容器begin开始
*/
#include<iostream>
#include<algorithm>
using namespace std;
template <class T>
void print(T x)
{
cout << x << endl;
}
int main()
{
int a[] = {1,2,3,4,5,6,7,8,9} ;
int b[] = {9,8,7,6,5,4,3,2,1} ; //
copy(a,a+5,b); //复制前五个
for_each(b,b+9,print<int>);
}

6. count

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
count(begin,end, int) 大于int型的数
count_if(begin,end,fun) 自定义函数
*/

#include<iostream>
#include<algorithm>
using namespace std;
template <class T>
void print(T x)
{
cout << x << endl;
}

int main()
{
int a[10] = {1,2,3,4,5,5,7,8,9,10};
cout << count(a,a+10,10);
//for_each(a,a+9,print<int>) ;
}

7. erase()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
using namespace std;
void fun(string &str)
{
str.pop_back();
}
int main()
{
string s= "123456";
cout << s << endl;
fun(s);
cout << s << endl;
//删除某一段的数值
s.erase(s.end()-2,s.end()-1);
cout << s << endl;
}

8. find_if()

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
/*
find_if(begin,end,greatThree)
找到大于三的所以所有数,return 首地址 就是一个数组
*/

#include<iostream>
#include<algorithm>
using namespace std;
bool greatThree(int x)
{
if(x > 3)
return true;
else
return false;
}
template <class T>
void print(T x)
{
cout << x << endl;
}

int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = find_if(a,a+10,greatThree) ;
for(int i = 0;i < 7;i++)
cout << *p++ <<endl;

//for_each(a,a+9,print<int>) ;
}

9 find

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
find返回找到元素的地址
*/

#include<iostream>
#include<algorithm>
using namespace std;
template <class T>
void print(T x)
{
cout << x << endl;
}

int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
cout << find(a,a+10,6);
}

10.for_each()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream> 
#include<algorithm>
using namespace std;
template <class T>
void print(T x)
{
cout << x << endl;
}

int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
for_each(a,a+10,print<int>);
}

11.itoa

int类型换成char类型 还可以设置转换进制
十进制可以转换成任意进制

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
int 类型换成string类型
*/
#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
int a = 64;
char b[3];
itoa(a,b,8); //8表示转换后的进制
cout << b[0] << b[1] << b[2];
}

12. max_element 和 min_element 求最大最小元素

1
2
3
4
5
6
7
8
9
10
11
12
/*
*max_element(begin,end)
求最大成员
*/
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int a[] = {1,2,5,6,3,4,8,9,7} ;
cout << *max_element(a,a+9);
}

13. memset 初始化

  • 可以如下替代

    1
    2
    3
    4
    5
    6
    7
    8
    #include<iostream>
    using namespace std;
    int main()
    {
    int a[10],b[10] = {1,2,3};
    for(int i = 0;i < 10;i++)
    cout << a[i] << " " << b[i] << endl;
    }
  • memset

1
2
3
4
5
6
7
8
9
10
11
12
/*
初始化数组
*/
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int a[10] ;
memset(a,0,10); //十个全部放0

}

14.replace_if() 满足条件的替换

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
/*
replace_if(begin,end,fun,int)将满足fun条件的换成int
replace(begin,end,3,5) 将所以的3替换成5
*/

#include<iostream>
#include<algorithm>
using namespace std;
bool greatTree(int x)
{
if(x > 3)
return true;
else
return false;
}
template <class T>
void print(T x)
{
cout << x << endl;
}

int main()
{
int a[] = {1,2,3,4,5,6,7,8,9} ;
replace_if(a,a+9,greatTree,9);//大于三的数替换成9
for_each(a,a+9,print<int>) ;
}

15.strstr() char*类型找到子串

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
int main()
{

char* str = "I am a Android developer!";
char* subStr = "Android";
char* result = strstr(str, subStr); //找到子串后面的字符串
printf("result = %s\n", result);//结果:result = Android developer!
return 0;
}

16. substr() 截取字符

1
2
3
4
5
6
7
8
9
#include<iostream>
using namespace std;
int main()
{
string str = "123456789";

//__LONG_LONG_MAX__ a = 18374001125;
cout << str.substr(2,3); //截取第i个字符后面三个
}

17.计时 getTIckCount()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
long n = 1000000000;
long t1 = GetTickCount();
//...娴嬭瘯浠g爜
while(n--);
long t2 = GetTickCount();
cout << "time:"<<(int(t2)-int(t1)) << endl;
return 0;
}

18.toupper() 和 tolower 字符的变换

1
2
3
4
5
6
7
8
9
#include<iostream>
using namespace std;
int main()
{
string a = "oIu";
a[0] = toupper(a[0]);
a[0] = tolower(a[1]);
cout << a;
}

19. 去重复unique() 必须已经排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<algorithm>
using namespace std;
void print(int a)
{
cout <<a << " ";
}
int main()
{
int a[6] ={1,1,2,2,3,3};
for_each(a,a+6,print);
cout << endl;
int pos = unique(a,a+6)-a;
for_each(a,a+6,print);
cout << endl;
}

20. 判断isalpha()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
判断字符或数字
*/

#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
char a = 'r' ,b = '1';
if(isalpha(a))
cout << "ok" ;
if(isdigit(b))
cout << "ko";

}

21. 取第k位数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h> 
int len(int x){
if(x<10) return 1;
return len(x/10)+1;
}

// 取x的第k位数字
int f(int x, int k){
if(len(x)-k==0) return x%10;
return f(x/10,3); //填空
}

int main()
{
int x = 23574;
printf("%d\n", f(x,3));
return 0;
}

交并集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<sstream>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void print(int n)
{
cout << n << " ";
}
int main()
{
vector<int> v1 = {1,2,3},v2={2,3,4},v3;
//差集
// set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), inserter(v3, v3.begin()));
// 交集
// set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), inserter(v3, v3.begin()));
//并集
set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), inserter(v3, v3.begin()));
v1 = v3;
for_each(v1.begin(),v1.end(),print);
}

vector 通过值删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void print(int n)
{
cout << n << " ";
}
int main()
{
vector<int> v={1,2,3,4,5};
v.erase(remove(v.begin(),v.end(),3));
for_each(v.begin(),v.end(),print);
}

JVM

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试
  • JVM 内存模型

    • 线程共享

      • 堆和方法区
    • 线程私有

      • 虚拟机栈 本地方法栈 程序计数器
    • 方法区:

    原来是通过永久代来实现,现在通过元空间实现,永久代是堆的一部分,元空间属于本地内存。元空间主要存储元信息,静态变量和常量池并入堆中。

    静态变量 静态代码块 静态方法 构造代码块

  • 堆

    对象的非静态成员变量

  • 栈内存

    存储局部变量

类加载机制

​ 七个阶段: 加载 验证 准备 解析 初始化 使用 卸载

  • 加载

    - 通过一个类的权限域名获取他的二进制字节流
       - 将二进制字节流代表的静态存储结构转化为方法区运行的数据结构
    - 将java 堆生成代表这个类的class 对象作为读取方法区数据的访问入口
- Xmx 最大堆内存  Xms 初始堆内存

四大引用

强引用我们平常new 这个对象

软引用:内存空间够就不会回收大

弱引用,不管空间是否够都能引用他。

虚引用主要用来跟踪垃圾回收的过程。

什么可以作为GCRPOOT 的引用对象

java 虚拟机栈中的引用对象

方法区中类静态属性引用对象

方法区产常量引用对象

本地方法栈中的引用对象

GC 回收的过程

1、发生Young GC之前进行检查,如果“老年代可用的连续内存空间” < “新生代历次Young GC后升入老年代的对象总和的平均大小”,说明本次Young GC后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,此时会触发FullGC

2、当老年代没有足够空间存放对象时,会触发一次FullGC

3、如果元空间区域的内存达到了所设定的阈值-XX:MetaspaceSize=,也会触发FullGC。

String Stringbuffer 是线程安全的 StringBuilder线程不安全

spring

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试
  • 切面编程,

    AOP 的实现关键在于代理

    代理分为静态代理和动态代理。

    静态代理时AspectJ

    动态代理有CGlib 和 jdk

    JDK动态代理只提供接口的代理,不支持类的代理

    CGlib是一个代码生成类库 通过继承方式实复写特定方法实现代理。

常用注解

1. 注册bean 对象

@Component kəmˈpoʊnənt

@Controller

@Service

@Repository

@bean

2. 自动装配

@Autowired waɪərd

Qualifier kwɑːlɪfaɪər

@Resource

@Value

3. bean 的范围

@Scope

4. 生命周期相关

@PostConstruct

@PreDestroy

前端控制器

前端控制器 去找处理映射器 得到一个执行链

前端控制器再去调用处理适配器 找到对应的controller 返回modelandview

在去调用视图解析器 返回view 主要是填充页面的参数

渲染完成后返回给view 试图

bean 的作用范围

单例

prototype

request

session

global-session

###

计算机网络

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试
  • http
    • 报文的结构 :请求行、请求头部、空行和请求数据4个部分组成
    • 端口 80
    • 明文传输
    • HTTP1.0 和 1.1 的区别
      • 持久链接 还提供身份认证
  • HTTP响应也由三个部分组成,分别是:状态行、消息报头、响应正文。
  • TCP 如何保证有效连接(运输层)

    • 确认和重传
    • 数据效验
    • 流量控制:当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。
    • 拥塞控制:当网络拥塞时,减少数据的发送。
  • 滑动窗口

    • 三个窗口 : 发送窗口 接受窗口 拥塞窗口
  • 输入URL 后面发生的事情

    • 查找 地址浏览器的缓存记录
    • 如果就需要找域名服务器 迭代查询 递归查询过
    • 找到Ip 建立链接
    • http发起请求 服务器响应
    • 渲染页面 构建dom 树
  • Ip和mac 地址

    • Ip 地址确定 主机的拓扑位置 物理地址区分不同主机的编号
    • mac是一个身份标识
    • IP 是动态变化的 类比家庭住址和身份证
  • 慢开始 拥塞避免 快重传

    • 连接建立好后,初始拥塞窗口的大小为1 表明可以传一个MSS 大小的数据

    在到达门限阈值之后每收到一个ACK窗口值就翻倍

    • 到了门限阈值后收到ACK就一步一步增加1,
    • 收到三个重复ACK 就将门限阈值提到变为当前的一半,再执行加法增大
  • TCP UDP 传输层

    TCP是可靠的

    ​ TCP 通过拥塞控制 确认机制来保证可靠性

    UDP 不保证可靠性

  • HTTP HTTPS

    HTTPS 其实就是加密的HTTP

集合框架

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试

Hashmap 的特性

  1. hashmap特性

    hashmap 可以实现快速存取 key 允许为null

    非同步 线程不安全

    底层时hash表

  2. hashmap 的底层实现原理

    底层时数组加链表 put get存取对象 当执行put 方法时 , 先对键值计算hashcode()得到它在bucket数组的位置。获取对象时,先得到bucket的位置 在调用equals 找到需要的值。

  1. put 方法的流程

    1. 计算机hashcode
    2. 判断hash表是否为空
    3. 发生碰撞放到散列表里去
    4. hashcode 值相同 三种情况
      1. equals 判断是否有相同
      2. 红黑树就调用红黑树的插入方法
      3. 链表就在尾部插入 如果插入链表个数为8 就转变为红黑树
    5. 如果满了就扩容。
  1. hashmap 什么时候需要扩容

    1. 通过判断数组容量是否大于0 判断数组是否初始化过
    2. 没有初始化
      1. 是否初始化默认大小
      2. 是否初始化容量
      3. 扩容两倍将元素重新运算复制到新的散列表中

5.谈一下hashMap中get是如何实现的?

对key的hashCode进行hashing,与运算计算下标获取bucket位置,如果在桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找,如果有hash冲突,则利用equals方法去遍历链表查找节点。

  1. hashmap 和 hashtable 的区别

    1. 相同点

      1. 都是key-value 存储

        1. HashMap允许Key-value为null,hashTable不允许;
        2. hashMap没有考虑同步,是线程不安全的。hashTable是线程安全的,给api套上了一层synchronized修饰;
          1. hashmap 的初始容量是16 hashtable 的初始容量是 11 (2*n+1)
          2. hashmap 自定义的hash算法 hashtable 没有自定义hash算法
      2. treemap 一般按照key 排序

String StringBuffer StringBuilder

Stringbuffer 是线程安全的 StringBuilder线程不安全

JUC

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试

synchronized

  • synchronized 的修饰对象

    • 静态方法 获得本类对象
    • 方法 本实例对象
    • 代码块: 可以指定锁对象
  • 原理

    当程序执行到synchronized 修饰段的时候,线程会尝试获取它的监视器对象

    如果监视器进入数为0 则该线程获得监视器,然后设置进入树为1 可重入

    如果monitor 对象已经被其他线程获取,则该线程进入阻塞状态,直到monitor 进入数为0

  • wait notify

    wait 和 notify 就是一个暂停运行 一个通知运行,当时必须获得锁以后才可以执行该对象,而且获得的锁必须是相同的锁机制。

    锁的原理也是获得监控器的对象,

    wait 立刻释放锁

    notify 一次只唤醒一个线程且唤醒的顺序和执行wait方法的顺序一致

  • volatile 关键字

    保证可见性

    不保证原子性

    禁止指令重排

守护进程和用户进程

用户进程就是用户创建的进程

不需要上乘逻辑介入

主线程结束 自动结束

普通线程是一直run 完 可能

阻塞队列

  • 普通阻塞队列

  • 数组阻塞队列

    一旦指定了队列的长度,则队列的大小不能改变 先进先出 数组实现

  • 列表阻塞队列

    先进先出 可以设置有限也可以设置无限

  • 优先阻塞队列

    插入的对象必须可以比较的

  • 异步阻塞队列

    put 必须等待take take也必须等待put

  • lock 和 synchronized 的区别

    lock 是一个类 发送异常不会释放锁

    synchoronized 不会释放锁

线程池

  • 线程池的配置

    CPU 密集性 +1

    IO密集型 CPU/(1-阻塞系数)

  • 线程池的参数

    核心线程数

    最大线程数

    存活时间

    存活时间单位

    任务队列

    线程工厂

    拒绝策略

    拒绝策略比如不管什么情况直接抛出异常

    或者任何处理继续运行

  • 线程池的创建

    1.newCachedThreadPool创建一个可缓存线程池程

    2.newFixedThreadPool 创建一个定长线程池

    3.newScheduledThreadPool 创建一个定长线程池

    4.newSingleThreadExecutor 创建一个单线程化的线程池

锁机制

公平锁就是按申请顺序执行

非公平锁就是部分优先级高的可以加塞

可重入锁就是进入锁内部仍然可以获得该锁

不停地空耗CPU

中心锁默认是非公平的

乐观锁默认操作不会修改数据 使用CAS

悲观锁默认会修改数据 使用Synchronized

在对记录进行修改前,先尝试为该记录加上排他锁(exclusive locks)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

期间如果有其他对该记录做修改或加排他锁的操作,都会等待解锁或直接抛出异常。

死锁

死锁预防是添加某种限制条件

比如设定某线程必须在另一个线程全部执行完之后才能执行

sleep yeild

①sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

AQS 抽象对垒同步器

mybaties

Posted on 2021-02-28 | Edited on 2021-03-03 | In 面试

myabties 执行器

SIMPLE 方式

从执行日志可以看出, 每次插入操作, 都会执行编译, 设置参数, 执行sql操作.

REUSE 方式

从执行日志可以看出, 只有第一次插入操作, 执行了sql编译步骤, 对其它插入操作执行了设置参数, 执行sql的操作.

批量

从执行日志可以看出, 只对第一次插入操作执行了sql编译操作, 对其它插入操作仅执行了设置参数操作, 最后统一执行.

常见问题

答:不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践而已。

12…4
Author

Author

40 posts
10 categories
14 tags
GitHub 简书
Links
  • csdn
  • github
© 2021 认识世界 认识你自己