Rao's Blog

  • 首页

  • 标签

  • 分类

  • 归档

  • 搜索

Java · 框架 · MyBatis

发表于 2019-11-25 | 更新于 2019-11-28 | 分类于 Java

简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

原理

MyBatis 的基本工作原理是:

  • 先封装 SQL
  • 接着调用 JDBC 操作数据库
  • 最后把数据库返回的表结果封装成 Java 类

使用

如果使用 Maven 来构建项目,则需将下面的 dependency 代码置于 pom.xml 文件中:

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>

实践

使用 MyBatis 实现数据库的增删改查:

  • 表 user
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`sex` char(1) NOT NULL COMMENT '性别',
`address` varchar(255) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

mysql> select * from user;
+----+----------+---------------------+-----+--------------------+
| id | username | birthday | sex | address |
+----+----------+---------------------+-----+--------------------+
| 1 | rao | 1990-08-07 00:00:00 | 男 | 陕西省西安市 |
| 2 | yu | 1990-01-02 00:00:00 | 女 | 山东省菏泽市 |
| 3 | rao | 2019-11-24 04:54:31 | 女 | 山东省青岛市 |
+----+----------+---------------------+-----+--------------------+
  • 主配置文件 SqlMapperConfig.xml
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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- MyBatis主配置文件 -->
<configuration>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql环境 -->
<environment id="mysql">
<!-- 配置事务类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>

<!-- 指定映射配置文件的位置 -->
<mappers>
<!-- XML方式 -->
<mapper resource="com/rao/dao/IUserMapper.xml"/>
<!-- 注解方式 -->
<!--mapper class="com.rao.dao.IUserDao"/-->
</mappers>
</configuration>
  • 实体类 User.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.rao.domain;

import java.io.Serializable;
import java.util.Date;

/**
* user表实体类
*
* @author Rao Hui
* @date 2019-11-24 15:12
*/
public class User implements Serializable {

private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
  • Dao 接口 IUserDao.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
package com.rao.dao;

import com.rao.domain.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
* 用户的持久层接口
*
* @author Rao Hui
* @date 2019-11-24 15:17
*/
public interface IUserDao {

/**
* 查询用户
* @return
*/
//@Select("select * from user") // 注解方式
List<User> findAll();

/**
* 保存用户
*/
void saveUser(User user);

/**
* 更新用户
*/
void updateUser(User user);

/**
* 删除用户
*/
void deleteUser(Integer userId);
}
  • 映射配置文件 IUserMapper.xml
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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.rao.dao.IUserDao">
<!-- 查询用户 -->
<select id="findAll" resultType="com.rao.domain.User">
select * from user;
</select>

<!-- 插入用户 -->
<insert id="saveUser" parameterType="com.rao.domain.User">
insert into user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>

<!-- 更新用户 -->
<update id="updateUser" parameterType="com.rao.domain.User">
update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}
</update>

<!-- 删除用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{uid}
</delete>
</mapper>
  • 接口测试类 MybatisTest.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package com.rao.test;

import com.rao.dao.IUserDao;
import com.rao.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
* mybatis入门测试
*
* @author Rao Hui
* @date 2019-11-24 15:49
*/
public class MybatisTest {

private InputStream in;
private SqlSession session;
private IUserDao userDao;

@Before
public void init() throws IOException
{
// 1. 读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");

// 2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);

// 3. 使用工厂生产SqlSession对象
session = factory.openSession();

// 4. 使用SqlSession创建Dao接口的代理对象
userDao = session.getMapper(IUserDao.class);
}

@After
public void destroy() throws IOException
{
session.commit();

// 释放资源
session.close();
in.close();
}

@Test
public void testFindAll(){

// 5. 使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users)
{
System.out.println(user);
}
}

@Test
public void testSaveUser()
{
User user = new User();
user.setUsername("hui");
user.setSex("男");
user.setAddress("山东省青岛市");
user.setBirthday(new Date());

userDao.saveUser(user);
}

@Test
public void testUpdateUser()
{
User user = new User();
user.setId(3);
user.setUsername("liu");
user.setSex("女");
user.setAddress("山东省青岛市");
user.setBirthday(new Date());

userDao.updateUser(user);
}

@Test
public void testDeleteUser()
{
userDao.deleteUser(4);
}
}

参考

来源

Java · 高级特性

发表于 2019-11-20 | 更新于 2019-11-26 | 分类于 Java

反射 (Reflection)

简述

反射机制:在运行状态中,可以动态访问 Java 对象的属性、方法、构造方法等。

场景:很多框架都运用了反射原理,例如 MyBatis 的实体类,Spring 的 AOP 等都有反射的实现。

相关类

  • java.lang.Class:代表类的实体,在运行的 Java 应用程序中表示类和接口
  • java.lang.reflect.Method:代表类的方法
  • java.lang.reflect.Field:代表类的成员变量
  • java.lang.reflect.Constructor:代表类的构造方法

Class

  • 获取类相关方法
方法 用途
asSubclass(Class clazz) 把传递的类的对象转换成代表其子类的对象
Cast 把对象转换成代表类或是接口的对象
getClassLoader() 获得类的加载器
getClasses() 返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className) 根据类名返回类的对象
getName() 获得类的完整路径名字
newInstance() 创建类的实例
getPackage() 获得类的包
getSimpleName() 获得类的名字
getSuperclass() 获得当前类继承的父类的名字
getInterfaces() 获得当前类实现的类或是接口
  • 获取类中属性相关的方法
方法 用途
getField(String name) 获得某个公有的属性对象
getFields() 获得所有公有的属性对象
getDeclaredField(String name) 获得某个属性对象
getDeclaredFields() 获得所有属性对象
  • 获取类中构造器相关的方法
方法 用途
getConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getConstructors() 获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() 获得该类所有构造方法
  • 获得类中方法相关的方法
方法 用途
getMethod(String name, Class…<?> parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法
  • 获得类中注解相关的方法
方法 用途
getAnnotation(Class annotationClass) 返回该类中与参数类型匹配的公有注解对象
getAnnotations() 返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass) 返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations() 返回该类所有的注解对象

Field

方法 用途
equals(Object obj) 属性与obj相等则返回true
get(Object obj) 获得obj中对应的属性值
set(Object obj, Object value) 设置obj中对应属性值

Method

方法 用途
invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法

Constructor

方法 用途
newInstance(Object… initargs) 根据传递的参数创建类的对象

实践

  • 实体类 Book.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* Book实体类
*
* @author Rao Hui
* @date 2019-11-26 09:39
*/
public class Book {

private final static String TAG = "BookTag";

private String name;
private String author;

@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}

public Book(){

}

public Book(String name, String author) {
this.name = name;
this.author = author;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

private String declareMethod(int index){
String string = null;
switch (index)
{
case 0:
string = "I am declaredMethod 1 !";
break;
case 1:
string = "I am declaredMethod 2 !";
break;
default:
string = "I am declaredMethod 1 !";
}

return string;
}
}
  • 反射类 ReflectBook.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* Book实体类反射测试
* @author Rao Hui
* @date 2019-11-26 09:44
*/
public class ReflectBook {

public static void main(String[] args){
try {

// 反射创建对象
reflectNewInstance();

// 反射私有构造方法
reflectPrivateConstrcutor();

// 反射私有方法
reflectPrivateMethod();

// 反射私有属性
reflectPrivateField();

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 反射创建对象
*/
public static void reflectNewInstance() throws Exception
{
Class<?> classBook = Class.forName("Book");
Object objectBook = classBook.newInstance();
Book book = (Book)objectBook;
book.setName("SRE运维解密");
book.setAuthor("Google");
System.out.println(book.toString());
}

/**
* 反射私有构造方法
*/
public static void reflectPrivateConstrcutor() throws Exception
{
Class<?> classBook = Class.forName("Book");
Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class,String.class);

//取消权限控制检查
declaredConstructorBook.setAccessible(true);
Book book = (Book)declaredConstructorBook.newInstance("高性能 MySQL", "hui");
System.out.println(book.toString());
}

/**
* 反射私有方法
*/
public static void reflectPrivateMethod() throws Exception
{
Class<?> classBook = Class.forName("Book");
Method method = classBook.getDeclaredMethod("declareMethod", int.class);
method.setAccessible(true);

// 传递object对象及参数调用该对象对应的方法
String string = (String)method.invoke(classBook.newInstance(), 0);
System.out.println(string);
}

/**
* 反射私有属性
*/
public static void reflectPrivateField() throws Exception
{
Class<?> classBook = Class.forName("Book");
Object objectBook = classBook.newInstance();
Field fieldTag = classBook.getDeclaredField("TAG");
fieldTag.setAccessible(true);
String tag = (String) fieldTag.get(objectBook);
System.out.println(tag);
}
}

权限申请

发表于 2019-11-19 | 更新于 2019-11-21 | 分类于 其他

服务器

  • 惠普即需即供:dts_jxjg@dxc.com,DXC 热线:68066686

  • 东软大数据即需即供:dts.dsj@neusoft.com,DSJ 热线:15318710660

  • 申请目标服务器:10.163.192.0/19,端口:3306

特权账号

林兆磊 01460160,张加彬 a0021120

监控

李锦涛 18002036

Java · 基本程序设计

发表于 2019-11-18 | 更新于 2019-11-25 | 分类于 Java

命名

  • 包名:统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。

    1
    正例:应用工具类包名为 com.alibaba.ai.util、类名为 MessageUtils
  • 类名:使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等。

    • 抽象类名:使用 Abstract 或 Base 开头。
    • 异常类名:使用 Exception 结尾。
    • 测试类名:以它要测试的类的名称开始,以 Test 结尾。
    1
    2
    正例:JavaServerlessPlatform / UserDO / XmlService / TcpUdpDeal / TaPromotion 
    反例:javaserverlessplatform / UserDo / XMLService / TCPUDPDeal / TAPromotion
  • 方法名、参数名、成员变量、局部变量:都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。

    1
    正例:localValue / getHttpMessage() / inputUserId
  • 常量名:全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。

    1
    2
    正例:MAX_STOCK_COUNT / CACHE_EXPIRED_TIME 
    反例:MAX_COUNT / EXPIRED_TIME
  • 各层命名规范

    • Service/DAO 层方法命名
      • 获取单个对象的方法用 get 做前缀
      • 获取多个对象的方法用 list 做前缀,复数形式结尾如:listObjects
      • 获取统计值的方法用 count 做前缀
      • 插入的方法用 save/insert 做前缀
      • 删除的方法用 remove/delete 做前缀
      • 修改的方法用 update 做前缀
    • 领域模型命名
      • 数据对象:xxxDO,xxx 即为数据表名
      • 数据传输对象:xxxDTO,xxx 为业务领域相关的名称
      • 展示对象:xxxVO,xxx 一般为网页名称
      • POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO

注释

注释类型

  • 单行注释://
  • 多行注释:/*..*/
  • 文档注释:/**..*/

注释规范

  • 类、类属性、类方法的注释必须使用 Javadoc 规范,使用 /**..*/ 格式。
  • 抽象方法必须要用 Javadoc 注释、除了返回值、参数、 异常说明外,还必须指出该方法实现的功能。
  • 所有的类都必须添加创建者和创建日期。
  • 方法内部单行注释。
  • 所有的枚举类型字段必须要有注释,说明每个数据项的用途。

数据类型

Java 中,一共有 8 种基本类型,其中有 4 种整型、2 种浮点类型、1 种字符类型、1 种布尔类型。

整型

类型 存储 取值范围
int 4 字节 -2147483648 ~ 2147483647(约20亿)
short 2 字节 -32768 ~ 32767
long 8 字节 -9223372036854775808 ~ 9223372036854775807
byte 1 字节 -128 ~ 127

提醒:Java 没有任何无符号类型(unsigned),且整型的范围与运行 Java 代码的机器无关。

浮点型

类型 存储 取值范围
float 4 字节 有效位数 6~7 位
double 8 字节 有效位数 15 位

警告:浮点数值不适用于禁止出现舍入误差的金融计算中。

char

char 类型用于表示单个字符,是一个单一的 16 位 Unicode 字符,最小值是 \u0000(即为 0),最大值是 \uffff(即为 65,535),建议不要在程序中使用 char 类型。

boolean

布尔类型有两个值:false 和 true,用于判定逻辑条件,整型值和布尔值之间不能进行相互转换。

变量

在 Java 中,每一个变量属于一种类型(Type),在声明变量时,变量所属的类型位于变量名之前,声明变量之后,必须用赋值语句对变量进行显式初始化。

1
2
3
4
5
double salary = 6500.0;
int vacationDays = 12;
long earthPopulation = xx;
boolean done = false;
Box box = new Box();

常量

在 Java 中,利用关键字 final 指示常量,final 表示这个变量只能被赋值一次,一旦赋值后就不能改再修改了,习惯上常量名使用全大写。

1
final double CM_PER_INCH = 2.54;

运算符

优先级 运算符 简介 结合性
1 [ ]、.、( ) 方法调用,属性获取 从左向右
2 !、~、 ++、 – 一元运算符 从右向左
3 * 、/ 、% 乘、除、取模(余数) 从左向右
4 + 、 - 加减法 从左向右
5 <<、 >>、 >>> 左右位移 从左向右
6 < 、<= 、>、 >=、 instanceof 对象是否属于同类型 从左向右
7 == 、!= 是否相等 从左向右
8 & 按位与 从左向右
9 ^ 按位异或 从左向右
10 | 按位或 从左向右
11 && 短路与 从左向右
12 || 短路或 从左向右
13 ?: 三元运算符 从右向左
14 =、 += 、-= 、*= 、/=、 %=、 &=、 |=、 ^=、 <、<= 、>、>= 、>>= 混合赋值运算符 从右向左

提醒:&& 和 || 是按照“短路”方式求值,如果第一个操作数已经能够确定表达式的值,第二个操作数就不必要计算了。& 和 | 这两个运算符与前面非常相似,只是不按“短路”方式计算,即在得到计算结果之前,一定要计算两个操作数的值。

字符串

从概念上讲,Java 字符串就是 Unicode 字符序列。Java 没有内置的字符串类型,而是在标准 Java 类库中提供了一个预定义类,叫做 String。Java 有自动垃圾回收机制,如果一块内存不再使用了,系统最终会将其回收。

  • 检测字符串是否相等:使用 equals 方法,不区分大小写使用 equalsIgnoreCase 方法,不要使用 == 运算符。

  • 空串:空串 “” 是长度为 0 的字符串,用以下方式可以检查是否为空。

1
2
if (str.length() == 0)
if (str.equals(""))
  • Null 串:表示目前没有任何对象与该变量关联,检查一个字符串既不是 null 也不为空串。
1
if (str != null && str.length() != 0)
  • 字符串 API:java.lang.string

输入输出

读取输入:使用 java.util.Scanner 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.*;

/**
* This program demonstrates console input.
* @version v1.0 2019-11-20
* @author Rao Hui
*/
public class Demo {
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);

// get frist input
System.out.print("What is your name? ");
String name = in.nextLine();

// get second input
System.out.print("How old are you? ");
int age = in.nextInt();

// dispaly output on console
System.out.println("Hello, " + name + ". Next year, you'll be " + (age + 1));
}
}

格式化输出:使用 System.out.printf()

  • d:整数类型
  • c:Unicode 字符
  • b:Boolean 值
  • s:String
  • f:浮点数(十进制)
  • e:浮点数(科学计数)
  • x:整数
  • h:散列码(十六进制)
  • %:字符 “%”

控制流

  • 条件语句:if (condition) statement
  • 循环:while (condition) statement、do statement while (condition)、for (int i = 1; i <= n; i++)
  • 多重选择:switch…case…
  • 中断控制:break(跳出循环)、continue(跳转到下一次循环)

数组

数组是一种数据结构,用来存储同一类型值的集合。用于数组的增强 for 循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {
public static void main(String args[]){
int[] numbers = {10, 20, 30, 40, 50};

for(int x : numbers ){
System.out.print( x );
System.out.print(",");
}
System.out.print("\n");
String[] names ={"James", "Larry", "Tom", "Lacy"};
for( String name : names ) {
System.out.print( name );
System.out.print(",");
}
}
}

关键字

类别 关键字 说明
访问控制 private 私有的
protected 受保护的
public 公共的
类、方法和变量修饰符 abstract 声明抽象
class 类
extends 继承
final 不可改变的
implements 实现(接口)
interface 接口
native 本地
new 创建
static 静态
strictfp 严格
synchronized 线程同步
transient 短暂
volatile 易失
程序控制 break 跳出循环
continue 继续
switch 根据值选择执行
case 定义一个值以供 switch 选择
default 默认
do 运行
if 如果
else 否则
for 循环
instanceof 实例
return 返回
while 循环
错误处理 assert 断言表达式是否为真
catch 捕捉异常
finally 有没有异常都执行
throw 抛出一个异常对象
throws 声明一个异常可能被抛出
try 捕获异常
包 import 引入
package 包
数据基本类型 byte 字节型
short 短整型
int 整型
long 长整型
float 单精度浮点
double 双精度浮点
char 字符型
boolean 布尔型
变量应用 super 超类
this 本类
void 无返回值
保留关键字 goto 是关键字,但不能使用
const 是关键字,但不能使用
null 空

Java · 开发环境

发表于 2019-11-18 | 更新于 2019-11-28 | 分类于 Java

下载

  • Java JDK
  • IntelliJ IDEA

搭建步骤

  • 安装
  • 配置环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# sudo vim /etc/profile

JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-13.0.1.jdk/Contents/Home"
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH:.
CLASS_PATH="$JAVA_HOME/lib"

# source /etc/profile

➜ ~ java -version
java version "13.0.1" 2019-10-15
Java(TM) SE Runtime Environment (build 13.0.1+9)
Java HotSpot(TM) 64-Bit Server VM (build 13.0.1+9, mixed mode, sharing)

~ root# echo $PATH
/Library/Java/JavaVirtualMachines/jdk-13.0.1.jdk/Contents/Home/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:.
~ root# echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk-13.0.1.jdk/Contents/Home
~ root# echo $CLASS_PATH
/Library/Java/JavaVirtualMachines/jdk-13.0.1.jdk/Contents/Home/lib
  • 配置 IDE(File -> Project Structure -> SDKs -> JDK home path)
1
2
3
4
5
6
7
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

Hello World!

Java 术语

术语名 缩写 解释
Java Development Kit JDK 编写 Java 程序的程序员使用的软件,包含编译器
Java Runtime Environmen JRE 运行 Java 程序的用户使用的软件,包含虚拟机
Standard Edition SE 用于桌面或简单服务器应用的 Java 平台
Enterprise Edition EE 用于复杂的服务器应用的 Java 平台
Micro Edition ME 用于手机或其他小型设备的 Java 平台
Data Access Object DAO 数据访问对象,主要是将数据库操作都封装起来,对外提供接口
Data Transfer Object DTO 泛指用于表示层与服务层之间的数据传输对象

Java 命令行工具

工具 说明 使用
javac Java 编译器,将 .java 编译成 .class 字节码文件 javac HelloWorld.java
java Java 执行程序的命令,执行 .class 文件 java HelloWorld

低空掠过,精确制导

发表于 2019-11-15 | 分类于 杂谈

蒋凡 谈职场进化历程,总结的八字经验:低空掠过,精确制导

低空掠过:对于和目标关联不大,客观上却必须做的事情,一定要以最小的代价和精力耗费量完成,不需要优秀。

精确制导:对于既定目标,就要精确锁定,排除干扰全力以赴,直到目标达成。比如编程,要钻研的很深,这是成长的敲门砖!

CentOS 6 与 CentOS 7 启停服务

发表于 2019-11-15 | 分类于 Linux

CentOS 6

1
2
3
4
5
6
7
8
# 设置服务自启动
chkconfig --add mysqld # 添加服务
chkconfig mysqld on # 开机自启服务
chkconfig mysqld off # 关闭开机自启
chkconfig --list | grep mysqld # 查看

# 查看状态、启动、停止、重启
service mysqld status/start/stop/restart

CentOS 7

1
2
3
4
5
systemctl enable mysqld.service  # 开机自启服务
systemctl disable mysqld.service # 关闭开机自启

# 查看状态、启动、停止、重启
systemctl status/start/stop/restart mysqld.service

MySQL · 实时会话解析

发表于 2019-11-15 | 分类于 MySQL

命令

  • show processlist,查看正在运行的线程,列出前 100 条
  • show full processlist,列出所有正在运行的线程

解析

1
2
3
4
5
6
7
8
9
10
mysql> show processlist;
+--------+---------+--------------------+--------------------+---------+------+----------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+--------+---------+--------------------+--------------------+---------+------+----------+------------------+
| 106125 | tdmsdev | 10.153.96.89:56808 | tdm | Sleep | 597 | | NULL |
| 106134 | tdmsdev | 10.153.96.89:56827 | tdm | Sleep | 596 | | NULL |
| 106178 | hdm | 10.133.0.53:60606 | information_schema | Sleep | 4 | | NULL |
| 106179 | sre | localhost | NULL | Query | 0 | starting | show processlist |
+--------+---------+--------------------+--------------------+---------+------+----------+------------------+
4 rows in set (0.00 sec)
  • Id:线程标识,kill 某线程时使用
  • User:显示当前用户,也就是执行 SQL 语句的用户
  • Host:显示执行 SQL 的 IP 和端口,可以用来追踪问题的来源
  • db:显示该线程连接的是哪个数据库
  • Command:显示当前执行的命令,一般:Sleep 休眠,Query 查询,Connect 连接,Binlog Dump 复制
  • Time:会话持续时间,单位(秒)
  • State:显示使用当前连接的状态,很重要列。请注意,State 只是语句执行中的某一个状态,以查询为例,需要经过 copying to tmp table,sorting result,sending data 等状态才算完成。
  • Info:显示执行的 SQL 语句,判断问题的重要依据。

State

  • Sleeping:已处理完,正在等待客户端发送新请求。
  • Sending data:线程正在处理 select 语句,并将数据发送到客户端。由于在此状态期间发生的操作往往会执行大量磁盘访问(读取),因此它通常是给定查询生命周期中运行时间最长的状态,属于慢查询。
  • Creating tmp table:正在创建临时表以存放部分查询结果。
  • Copying to tmp table on disk:由于临时结果集大于 tmp_table_size,正在将临时表从内存存储转为磁盘存储以此节省内存,可以通过变量 tmp_table_size 和 max_heap_table_size 来控制内存表大小上限。
  • Waiting for table flush:线程正在执行 flush tables 并且正在等待所有线程关闭它们的表。但是,要重新打开表,它必须等到所有其他线程关闭了相关表。
  • Writing to net:服务器正在将数据包写入网络。
  • Killed:通常发送了一个 kill 请求给某线程,某些情况下,线程可能仍然需要很短的时间才能死掉,如果线程被某个其他线程锁定,则一旦另一个线程释放其锁定,kill 就会马上生效。
  • System lock:正在等待取得一个外部的系统锁。如果当前没有运行多个 mysqld 服务同时请求同一个表,那么可以通过增加 --skip-external-locking 参数来禁止外部系统锁。

官方参考

MySQL · 健康检查

发表于 2019-11-15 | 分类于 MySQL

简介

MySQL 运行状况健康检查,提供技术评估和建议优化数据库,通过监控告警,从而优化模式、服务器配置、查询和复制,显著提高性能、可扩展性、可用性和安全性。

检查项

  • 架构:评估并推荐数据库架构和设计优化
  • 配置:评估 MySQL 配置并根据您的特定应用提出更改建议
  • 性能:监视查询并提出 SQL 代码更改建议,以提高性能
  • 性能:监视内存使用(缓存、命中率等)并提出更改建议
  • 备份:评估备份配置并提出更改建议,以提高备份/还原性能
  • 安全性:发现安全漏洞并推荐更严格的安全配置

对象

  • MySQL 应用开发
  • 项目经理
  • MySQL DBA

主题

  • MySQL 性能调优:基础知识或高级提示和技巧
  • MySQL 企业版:MySQL Enterprise Monitor、顾问程序、Query Analyzer、备份和分区
  • MySQL Workbench:通过设计提高数据库性能
  • MySQL 分区:改善高负载情况下的性能
  • MySQL 企业级备份:快速、一致的联机“热”备份

MySQL · 案例分析 · Waiting for table flush

发表于 2019-11-14 | 更新于 2019-11-15 | 分类于 MySQL

背景

MES 工厂反馈业务查询慢,登录数据库手工执行 SQL 操作也没有响应,怀疑是 02:00 执行的备份任务导致。

分析

  • 登录数据库,执行 show processlist 查看当前会话,发现大量线程状态为 Waiting for tables flush。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mysql> show processlist;
+---------+-----------------+----------------------+--------------------+-------------+-------+---------------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+---------+-----------------+----------------------+--------------------+-------------+-------+---------------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| 3074726 | cosmo_dsj | 10.138.225.194:41311 | NULL | Binlog Dump | 31808 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 3080884 | cosmo_t | % | cosmo_im_1021 | Connect | 12515 | Sending data | CALL procedure_imp_table |
| 3082179 | cosmo_t | 10.138.228.42:36560 | cosmo_im_1021 | Sleep | 19 | | NULL |
| 3082727 | root | localhost | NULL | Query | 6180 | Waiting for table flush | FLUSH NO_WRITE_TO_BINLOG TABLES |
| 3082888 | cosmo_r | 10.180.221.43:52153 | cosmo_im_1021 | Sleep | 5 | | NULL |
| 3082892 | cosmo_r | 10.180.221.43:52155 | cosmo_im_1021 | Sleep | 1 | | NULL |
| 3082919 | cosmo_t | % | cosmo_im_1021 | Connect | 6125 | Waiting for table flush | CALL procedure_assembly_work |
| 3082940 | cosmo_t | % | cosmo_im_1021 | Connect | 6104 | Waiting for table flush | UPDATE board_datas bo inner join (
SELECT times,
cNum |
| 3083094 | cosmo_t | 10.180.221.45:59111 | cosmo_im_1021 | Query | 6 | Waiting for table flush | SELECT a.*,TIMESTAMPDIFF(MINUTE,a.CallTime,NOW()) as Tdiff from
(SELECT DISTINCT pmcall.Call_ID ,ca |
| 3083127 | cosmo_t | % | cosmo_im_1021 | Connect | 5924 | Waiting for table flush | UPDATE board_datas bo inner join (
SELECT times,
cNum |
| 3083260 | cosmo_t | % | cosmo_im_1021 | Connect | 5744 | Waiting for table flush | UPDATE board_datas bo inner join (
SELECT times,
cNum |
  • 找到首次出现此状态执行的操作 FLUSH NO_WRITE_TO_BINLOG TABLES,执行时间 6125s,线程ID 3082727,这是 XtraBackup 执行全量备份的一个线程,主要作用是关闭所有打开的表,强制关闭所有正在使用的表,并刷新查询缓存和预准备语句缓存。

  • 备份正常执行这个操作是不会锁表的,但是如果在此期间存在慢查询 CALL procedure_imp_table,执行时间 12515s,线程ID 3080884,就会占用全局只读锁,阻止关闭打开的表。

  • 结论:使用 mysqldump、XtraBackup 备份期间出现了慢查询并且慢查询长时间阻塞,就会出现 Waiting for tables flush。

解决

  • 找出超时的慢查询,执行 kill 3080884 ,问题解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> kill 3080884;
Query OK, 0 rows affected (0.00 sec)

mysql> show processlist;
+---------+-----------------+----------------------+--------------------+-------------+-------+---------------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+---------+-----------------+----------------------+--------------------+-------------+-------+---------------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| 1 | event_scheduler | localhost | NULL | Daemon | 4 | Waiting for next activation | NULL |
| 3061488 | cosmo_t | 10.180.199.156:49161 | cosmo_im_1021 | Sleep | 34 | | NULL |
| 3074726 | cosmo_dsj | 10.138.225.194:41311 | NULL | Binlog Dump | 31920 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 3080883 | cosmo_t | 10.138.42.106:42146 | cosmo_im_1021 | Sleep | 144 | | NULL |
| 3081434 | cosmo_t | 10.138.42.106:44741 | cosmo_im_1021 | Sleep | 144 | | NULL |
| 3082179 | cosmo_t | 10.138.228.42:36560 | cosmo_im_1021 | Sleep | 131 | | NULL |
| 3082888 | cosmo_r | 10.180.221.43:52153 | cosmo_im_1021 | Sleep | 1 | | NULL |
| 3082892 | cosmo_r | 10.180.221.43:52155 | cosmo_im_1021 | Sleep | 4 | | NULL |
| 3083094 | cosmo_t | 10.180.221.45:59111 | cosmo_im_1021 | Sleep | 27 | | NULL |
| 3083531 | cosmo_r | 10.180.207.197:61769 | cosmo_im_1021 | Sleep | 3 | | NULL
1…567…18
Hui Rao

Hui Rao

最好的成长是分享
173 日志
19 分类
14 标签
GitHub E-Mail
© 2021 Hui Rao
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Gemini v7.1.0
|