0%

文章字数:392,阅读全文大约需要1分钟

ReflectionUtilsspring针对反射提供的工具类。

handleReflectionException异常处理

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void handleReflectionException(Exception ex) {
if (ex instanceof NoSuchMethodException) {
throw new IllegalStateException("Method not found: " + ex.getMessage());
}
if (ex instanceof IllegalAccessException) {
throw new IllegalStateException("Could not access method: " + ex.getMessage());
}
if (ex instanceof InvocationTargetException) {
handleInvocationTargetException((InvocationTargetException) ex);
}
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
throw new UndeclaredThrowableException(ex);
}

主要是将反射中的异常分成几个部分,规范化输出

  • boolean declaresException(Method method, Class<?> exceptionType)
    判断方法上是否声明了指定的异常类型

findField查找字段

  • Field findField(Class<?> clazz, String name, Class<?> type)

查找指定类的指定名称和指定类型的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static Field findField(Class<?> clazz, String name, Class<?> type) {
Class<?> searchType = clazz;
while (Object.class != searchType && searchType != null) {
Field[] fields = getDeclaredFields(searchType);
for (Field field : fields) {
if ((name == null || name.equals(field.getName())) &&
(type == null || type.equals(field.getType()))) {
return field;
}
}
searchType = searchType.getSuperclass();
}
return null;
}

获取所有的方法,然后循环遍历,知道找到满足条件的返回
其中getDeclaredFields(searchType)方法使用ConcurrentReferenceHashMapField缓存,并优先从缓存中取。

  • Field findField(Class<?> clazz, String name)

设置字段setField

  • void setField(Field field, Object target, Object value)设置指定字段的值
    直接使用Field.set/get方法,然后格式化处理了异常
  • Object getField(Field field, Object target)获取指定字段的值

查找方法findMethod

  • Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes)
    查找方法,方法的参数是一个可变长的Class

  • Method findMethod(Class<?> clazz, String name)直接查,不指定参数

调用方法invokeMethod

  • Object invokeMethod(Method method, Object target, Object... args)调用方法

  • Object invokeMethod(Method method, Object target)简单版本

判断类

  • boolean declaresException(Method method, Class<?> exceptionType)
    方法上是否声明了指定的异常

  • boolean isPublicStaticFinal(Field field)
    判断字段首付是public static final

  • boolean isEqualsMethod(Method method)
    判断方法是否是equals方法

  • boolean isHashCodeMethod(Method method)
    判断方法是否是hashcode方法

  • boolean isToStringMethod(Method method)
    判断方法是否是toString方法

  • boolean isObjectMethod(Method method)
    判断方法是否是Object类上的方法

操作

  • void makeAccessible(Field field)
    使私有的字段可写

  • void makeAccessible(Method method)
    私有方法可调用

  • void makeAccessible(Constructor<?> ctor)
    私有构造器可调用

  • void doWithLocalMethods(Class<?> clazz, MethodCallback mc)
    遍历类上的方法,并执行回调

1
2
3
public interface MethodCallback {
void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;
}
  • void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf)
    增加了一个方法过滤器
1
2
3
public interface MethodFilter {
boolean matches(Method method);
}

文章字数:191,阅读全文大约需要1分钟

使用ScheduledThreadPoolExecutor创建定时任务

现象

  1. 创建定时任务之后修改系统时间,以自测定时任务是否执行。发现未执行
  2. 不修改系统时间则正常

解决

  1. DelegatingErrorHandlingRunnable.class可以看到每次执行之后才会使用延时创建下一个时段的任务。所以即使是cron表达式创建的定时任务指定了下一次执行时间后就和系统时间没有关联了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public ScheduledFuture<?> schedule() {
    synchronized (this.triggerContextMonitor) {
    this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
    if (this.scheduledExecutionTime == null) {
    return null;
    }
    long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
    this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
    return this;
    }
    }

    @Override
    public void run() {
    Date actualExecutionTime = new Date();
    super.run();
    Date completionTime = new Date();
    synchronized (this.triggerContextMonitor) {
    this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
    if (!this.currentFuture.isCancelled()) {
    schedule();
    }
    }
    }
  2. 只能先修改时间再创建定时任务就可以解决问题。


文章字数:53,阅读全文大约需要1分钟

@Configuration注解的类就是配置文件,@Bean注解的方法就会注入名为方法名的实例

获取方法之一

1
2
3
4
5
6
7
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

// 获取配置文件
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
// 获取 bean文件
Person bean = context.getBean(Person.class);
System.out.println(bean);

文章字数:33,阅读全文大约需要1分钟

  • 字符串
    1
    2
    3
    4
    5
    @Value("${some.key:my default value}")
    private String stringWithDefaultValue;
    //空值
    @Value("${some.key:}")
    private String stringWithBlankDefaultValue;
  • 基本数据类型
    1
    2
    3
    4
    5
    @Value("${some.key:true}")
    private boolean booleanWithDefaultValue;

    @Value("${some.key:42}")
    private int intWithDefaultValue;
  • 数组默认值
    1
    2
    3
    4
    5
    @Value("${some.key:one,two,three}")
    private String[] stringArrayWithDefaults;

    @Value("${some.key:1,2,3}")
    private int[] intArrayWithDefaults;

文章字数:286,阅读全文大约需要1分钟

写了一个工具类,并且使用Spring注入了一个Service但是使用的时候返回null

分析

  1. 如果是找不到类应该在启动的时候报错,但是知道运行时才报空指针(@Autowired默认required = true)
  2. spring是在启动的时候扫描文件,将相应注解的bean保存,然后再统一注入
  3. 我的工具类是使用反射生成的实例,所以新的实例中没有注入的bean

解决

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BeanFactoryTest implements ApplicationContextAware {

private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}

public ApplicationContext getApplicationContext() {
return applicationContext;
}
}

手动获取bean

1
BlogService blogService=beanFactoryTest.getApplicationContext().getBean(BlogService.class);

其它

使用注入的类如果不是spring管理的注入也没有效果,即只有在bean中才能使用bean


文章字数:892,阅读全文大约需要3分钟

spring提供了注解形式的缓存,可以在方法查询了一次之后保存结果。但是内部调用不会触发缓存(this.xx())。

基础注解

  1. @Cacheable被标记方法执行后返回结果会被缓存。
  2. @CacheEvict方法执行前或后执行移除springCache中某些元素。

@Cacheable

标记方法支持缓存,执行一次后返回结果会被保存。拥有三个参数

  1. value指定缓存在哪个Cache上,指定多个Cache时是一个数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Cacheable("cache1")//Cache是发生在cache1上的
    public User find(Integer id) {
    returnnull;
    }
    //多个
    @Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
    public User find(Integer id) {
    returnnull;
    }
  2. key缓存的键,需要使用EL表达式。如果不指定,则缺省按照方法的所有参数进行组合

    1
    2
    3
    4
    5
    6
    7
    8
    9
    key="#id"//#参数名 使用参数值作为key
    key="#p0"//#p参数的index 使用第一个参数值作为key
    //使用spring提供的包含信息的root方法。root.可省略
    key="root.methodName"//当前方法名
    key="root.method.name"//当前方法
    key="root.targetClass"//当前被调用的对象
    key="root.targetClass"//对象Class
    key="root.args[0]"//当前方法组成的数值
    key="root.caches[0].name"//当前被调用的方法使用的Cache

    拼接:

    1
    2
    3
    4
    @Cacheable(key = "'com:test:'+#id")
    //使用全局变量防止多次对key赋值?
    public static final String KEY_NAME = "'com:test:'";
    @Cacheable(key = KEY_NAME +"+#id")
  3. condition指定发生条件
    也是EL表达式

    1
    2
    condition="#user.id%2==0"
    condition = "#key != null"

    @CachePut

    @Cacheable相似,只不过@CachePut不会检查是否缓存中存在结果,而是直接执行。

    1
    2
    3
    4
    5
    6
    //@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
    @CachePut("users")//每次都会执行方法,并将结果存入指定的缓存中
    public User find(User user) {
    System.out.println("find user by user " + user);
    return user;
    }

    @CacheEvict

    用来清除缓存,加在需要清除操作的 方法/类 上。

属性列表:valuekeyconditionallEntriesbeforeInvocation
@Cacheable相同意义的属性

  1. value表示清除操作是发生在哪些Cache上的(对应Cache的名称)
  2. keykey表示需要清除的是哪个key,如未指定则会使用默认策略生成的key
  3. conditioncondition表示清除操作发生的条件

其它属性

  1. allEntries allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。
    1
    2
    3
    4
    5
    //清除users
    @CacheEvict(value="users", allEntries=true)
    public void delete(Integer id) {
    System.out.println("delete user by id: " + id);
    }
  2. beforeInvocation设置
    清除默认是方法执行后,如果方法因异常没有成功返回则不会执行清除。设置这个能够在方法执行前清除。
    1
    2
    3
    4
    @CacheEvict(value="users", beforeInvocation=true)
    public void delete(Integer id) {
    System.out.println("delete user by id: " + id);
    }
    @Ehcache也有设置清除策略

@Caching

@Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。

1
2
3
4
5
@Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"),
@CacheEvict(value = "cache3", allEntries = true) })
public User find(Integer id) {
returnnull;
}

自定义注解中使用

Spring允许我们在配置可缓存的方法时使用自定义的注解,前提是自定义的注解上必须使用对应的注解进行标注。如我们有如下这么一个使用@Cacheable进行标注的自定义注解。

1
2
3
4
5
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Cacheable(value="users")
public @interface MyCacheable {
}

文章字数:157,阅读全文大约需要1分钟

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
-- 1. 查询死锁
select
request_session_id spid,
OBJECT_NAME(resource_associated_entity_id) tableName
from
sys.dm_tran_locks
where
resource_type='OBJECT'

-- 2. 查询相关资源
SELECT
der.[session_id],der.[blocking_session_id],
sp.lastwaittype,sp.hostname,sp.program_name,sp.loginame,
der.[start_time] AS '开始时间',
der.[status] AS '状态',
dest.[text] AS 'sql语句',
DB_NAME(der.[database_id]) AS '数据库名',
der.[wait_type] AS '等待资源类型',
der.[wait_time] AS '等待时间',
der.[wait_resource] AS '等待的资源',
der.[logical_reads] AS '逻辑读次数'
FROM sys.[dm_exec_requests] AS der
INNER JOIN master.dbo.sysprocesses AS sp ON der.session_id=sp.spid
CROSS APPLY sys.[dm_exec_sql_text](der.[sql_handle]) AS dest
--WHERE [session_id]>50 AND session_id<>@@SPID
ORDER BY der.[session_id]
GO

-- 3. 查询数据库状态
select name,user_access,user_access_desc,
snapshot_isolation_state,snapshot_isolation_state_desc,
is_read_committed_snapshot_on
from sys.databases

-- 4. 设置数据库为SINGLE_USER模式,减少锁定时间
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE dbname SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE dbname SET READ_COMMITTED_SNAPSHOT ON
ALTER DATABASE dbname SET MULTI_USER


-- 5. 设置session 的锁超时时间,仅对当前session有效
SET LOCK_TIMEOUT 3000 --毫秒ms
/* 1 s = 1000 ms
*/
select @@LOCK_TIMEOUT --默认值为-1,即无超时限制

文章字数:429,阅读全文大约需要1分钟

一、字符串相关

  1. LENGTH获取字节长度 select length('abcd')
  2. CONCAT拼接字符串 select concat('ab', 'cd')
  3. UPPER字符全转大写 select upper('abcd')
  4. LOWER字符全转小写 select lower('ABCD')
  5. SUBSTR从索引1开始,返回指定位置之后的字符 select substr('abcd', 2) => bcd; 从索引开始,获取指定长度 select substr('abcd', 1,3) => abc
  6. INSERT 返回第二个参数第一次出现的位置,1开始,没有返回0 select insert('abcd', 'cd') => 3
  7. TRIM 去除首尾指定的字符,如果没有指定,代表去除空格 select trim('-','-123-') => 123
  8. LPAD 用指定字符填充左长度,填充到指定长度 select lpad('12', 4, '0') => 0012
  9. RPAD 用指定字符填充右长度,填充到指定长度 select rpad('12',4,'#') => 12##
  10. REPLACE 替换所有字符串成另一个字符串 select replace('abcdef', 'bc', '#') => a#def

二、数学函数

  1. ROUND四舍五入 select round(-1.55) => -2; 保留指定位的小数 select round(1.2345, 2) => 1.23
  2. CEIL 向上取整 select ceil(-1.01) => -1
  3. FLOOR 向下取整 select floor(1.1) => 1
  4. TRUNCATE 保留几位小数 select truncate(1,2345, 2) => 1.23
  5. MOD 取模 select mod(10, 3) => 1

三、日期函数

  1. NOW 返回当前系统日期和时间
  2. CURDATE返回当前系统日期
  3. CURTIME返回当前时间
  4. MONTHNAME(NOW())返回当前月份英文
  5. DAYNAME(NOW())返回当前是周几英文
  6. SELECT STR_TO_DATE('4-3#1992', '%m-%d#%Y')日期格式化
  7. SELECT DATE_FORMAT(NOW(), '%m#%d#%Y')时间格式化

四、系统相关

  1. SELECT VERSION() sql 版本号
  2. SELECT DATABASE()当前数据库名
  3. SELECT USER()当前登录用户名

文章字数:353,阅读全文大约需要1分钟

一、ROW_NUMBER

作用:给查询的数据加上行号
例如:

1
select ROW_NUMBER() over(order by score desc) index,score,name from studentScore

查询学生的成绩score和名字name并且根据成绩排序order by score desc,最后加上行号ROW_NUMBER() over...

1
2
3
4
5
6
index|score|name
1 |100 |st1
2 |90 |st1
3 |90 |st1
4 |80 |st1
5 |70 |st1

二、RANK

作用:排名,如果有同名次的,会累加名次。比如找前5名,没有同名次的时候输出名次1,2,3,4,5的数据。如果有名次一样的,输出的则是名次1,2,2,4,5。

例如:

1
select RANK() over(order by studentScore desc) studentRank, * from studentScore
1
2
3
4
5
6
studentRank|score|name
1 |100 |st1
2 |90 |st1
2 |90 |st1
4 |80 |st1
5 |70 |st1

三、DENSE_RANK

作用:排名,区别于RANK。当有同名次的时候,不会累计,即有同名次是会显示名次1,2,2,3,4

例如:

1
select DENSE_RANK() over(order by studentScore desc) studentRank, * from studentScore
1
2
3
4
5
6
studentRank|score|name
1 |100 |st1
2 |90 |st1
2 |90 |st1
3 |80 |st1
4 |70 |st1

NTILE

作用:将数据切分成几个部分,并标记部分代号。比如NTILE(2),就是将所有数据平分成两个部分,一部分是1,另一部分是2

例如

1
select NTILE(2) over(order by studentScore desc) number,* from studentScore
1
2
3
4
5
6
studentRank|score|name
1 |100 |st1
1 |90 |st1
1 |90 |st1
2 |80 |st1
2 |70 |st1

关键词: sql

文章字数:269,阅读全文大约需要1分钟

作用

为前面的函数提供数据(分区排序,然后对每个分区都进行前面函数的操作)

查出每门功课的第一名

1
2
3
4
select * from(
select *, ROW_NUMBER() over(partition by coursename order by mark desc) ranks from stuMark
) sc where sc.ranks=1
)
  • partition by coursename将数据根据coursename进行分区,使各个学科的成绩分开
  • ROW_NUMBER()给每个分区的成绩单独加上行号
  • where sc.ranks=1选取行号为1即第一名的成绩数据

排名

1
select RANK() over(order by studentScore desc) studentRank, * from studentScore
  • overRANK函数指定数据内容,及通过分数排序的学生成绩

根据班级求总分

1
select t.name,t.class,t.sroce,sum(t.sroce) over(partition by t.class order by t.sroce desc) mm from T2_TEMP t;
  • 通过over(partition by...将数据分区
  • sum计算每个分区的总和

找出每个班级第一名和最后一名

1
2
select t.name,t.class,t.sroce,first_value(t.sroce) over(partition by t.class order by t.sroce desc) mm from T2_TEMP t;
select t.name,t.class,t.sroce,last_value(t.sroce) over(partition by t.class order by t.sroce desc) mm from T2_TEMP t;
  • 使用over分区
  • first_valuelast_value找出分区的第一名和最后一名

其它

1
2
3
4
5
6
7
8
9
count() over(partition by ... order by ...):求分组后的总数。
  max() over(partition by ... order by ...):求分组后的最大值。
  min() over(partition by ... order by ...):求分组后的最小值。
  avg() over(partition by ... order by ...):求分组后的平均值。
  lag() over(partition by ... order by ...):取出前n行数据。  

  lead() over(partition by ... order by ...):取出后n行数据。

  ratio_to_report() over(partition by ... order by ...):Ratio_to_report() 括号中就是分子,over() 括号中就是分母。