0%

DriverManager

在DriverManager加载时,会在静态代码块中调用loadInitialDrivers()加载默认jdbc驱动,默认会加载在系统属性jdbc.drivers中配置的驱动及通过SPI方式加载Driver.class,各驱动的Driver实现类会调用DriverManager.registerDriver()注册驱动。目前主流的驱动基本都使用SPI的方式加载,所以大部分驱动只需要引入依赖包既可,不需要手动注册。

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
public class DriverManager {
// 保存已经加载的jdbc Driver
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
static {
loadInitialDrivers();
}
// 加载默认jdbc驱动
private static void loadInitialDrivers() {
String drivers;
//获取系统属性jdbc.drivers,并加载已配置驱动
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
//spi的方式加载Driver驱动
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
}
return null;
}
});
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
for (String aDriver : driversList) {
try {
Class.forName(aDriver, true, ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
}

驱动管理相关方法,包括注册驱动、取消注册驱动,获取所有驱动

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
public class DriverManager {
// 保存已经加载的jdbc Driver
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
// 注册jdbc驱动
public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
registerDriver(driver, null);
}
// 注册jdbc驱动
public static synchronized void registerDriver(java.sql.Driver driver,DriverAction da)
throws SQLException {
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
throw new NullPointerException();
}
println("registerDriver: " + driver);

}
//取消注册驱动
@CallerSensitive
public static synchronized void deregisterDriver(Driver driver)
throws SQLException {
if (driver == null) {
return;
}
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
}
DriverInfo aDriver = new DriverInfo(driver, null);
if(registeredDrivers.contains(aDriver)) {
if (isDriverAllowed(driver, Reflection.getCallerClass())) {
DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
if(di.action() != null) {
di.action().deregister();
}
registeredDrivers.remove(aDriver);
} else {
throw new SecurityException();
}
} else {
}
}
//获取所有的jdbc驱动
@CallerSensitive
public static java.util.Enumeration<Driver> getDrivers() {
java.util.Vector<Driver> result = new java.util.Vector<>();
Class<?> callerClass = Reflection.getCallerClass();
for(DriverInfo aDriver : registeredDrivers) {
if(isDriverAllowed(aDriver.driver, callerClass)) {
result.addElement(aDriver.driver);
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
return (result.elements());
}
}

获取连接相关方法getConnection有多个重载方法,其最后都调用getConnection(String url, java.util.Properties info, Class<?> caller)方法。
最终会调用驱动的connect()方法获取连接

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
public class DriverManager {
// 获取jdbc连接
@CallerSensitive
public static Connection getConnection(String url,java.util.Properties info) throws SQLException {
return (getConnection(url, info, Reflection.getCallerClass()));
}
// 获取jdbc连接
public static Connection getConnection(String urlString user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
return (getConnection(url, info, Reflection.getCallerClass()));
}
// 获取jdbc连接
public static Connection getConnection(String url) throws SQLException {
java.util.Properties info = new java.util.Properties();
return (getConnection(url, info, Reflection.getCallerClass()));
}
// 获取Driver
@CallerSensitive
public static Driver getDriver(String url)throws SQLException {
Class<?> callerClass = Reflection.getCallerClass();
for (DriverInfo aDriver : registeredDrivers) {
if(isDriverAllowed(aDriver.driver, callerClass)) {
try {
if(aDriver.driver.acceptsURL(url)) {
return (aDriver.driver);
}
} catch(SQLException sqe) {
}
} else {
}
}
throw new SQLException("No suitable driver", "08001");
}
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
//获取调用类的类加载器,也就是调用DriverManager.getConnection()的类
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
SQLException reason = null;
for(DriverInfo aDriver : registeredDrivers) {
//确保记载Driver的类加载器调用类的类加载器是同一个
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
}
}
if (reason != null) {
throw reason;
}
throw new SQLException("No suitable driver found for "+ url, "08001");
}


}

总结:DriverManager有两个作用,一是用于管理jdbc驱动,二是用于获取jdbc连接,

Statement

  • 普通sql查询
  • 支持批量更新,批量删除;
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
99
100
101
102
public interface Statement extends Wrapper, AutoCloseable {
//执行查询,返回结果集 SELECT
ResultSet executeQuery(String sql) throws SQLException;
//执行更新sql语句, INSERT、UPDATE、DELETE,返回影响行数
int executeUpdate(String sql) throws SQLException;
void close() throws SQLException;
//获取statement对象所生成resultSet 象中的字符和二进制列值返回的最大字节数。此限制仅应用于 binary、varbinary、longvarbinary、char、varchar、nchar、nvarchar、longnvarchar和longvarchar 列。如果超过了该限制,则直接丢弃多出的数据。
int getMaxFieldSize() throws SQLException;
void setMaxFieldSize(int max) throws SQLException;
//获取 ResultSet能返回的最大行数
int getMaxRows() throws SQLException;
void setMaxRows(int max) throws SQLException;
//enable为true表示启用转义处理;为 false 表示禁用转义处理
void setEscapeProcessing(boolean enable) throws SQLException;
//查询超时时间
int getQueryTimeout() throws SQLException;
void setQueryTimeout(int seconds) throws SQLException;
//取消查询
void cancel() throws SQLException;
//获取此 Statement 对象上的调用报告的第一个警告
SQLWarning getWarnings() throws SQLException;
//清除在此 Statement 对象上报告的所有警告
void clearWarnings() throws SQLException;
//光标名称设置为给定的 String,后续 Statement 对象的 execute 方法将使用此字符串
void setCursorName(String name) throws SQLException;
//----------------------- Multiple Results --------------------------
//执行sql语句,如果第一个结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在任何结果,则返回 false
boolean execute(String sql) throws SQLException;
//获取结果集,配合execute()使用
ResultSet getResultSet() throws SQLException;
//获取影响行数,配合execute()使用
int getUpdateCount() throws SQLException;
//移动后续结果,如果其为 ResultSet 对象,则返回 true,配合execute()使用
boolean getMoreResults() throws SQLException;
//--------------------------JDBC 2.0-----------------------------
//设置结果集游标的方向,默认值是 ResultSet.FETCH_FORWARD ResultSet.FETCH_FORWARD,ResultSet.FETCH_REVERSE,ResultSet.FETCH_UNKNOWN
void setFetchDirection(int direction) throws SQLException;
int getFetchDirection() throws SQLException;
//控制的是从数据库向应用程序客户端发送数据的页面大小
void setFetchSize(int rows) throws SQLException;
int getFetchSize() throws SQLException;
int getResultSetConcurrency() throws SQLException;
//设置 ResultSet type ResultSet.TYPE_FORWARD_ONLY,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.TYPE_SCROLL_SENSITIVE
int getResultSetType() throws SQLException;
void addBatch( String sql ) throws SQLException;
void clearBatch() throws SQLException;
int[] executeBatch() throws SQLException;
Connection getConnection() throws SQLException;
//--------------------------JDBC 3.0-----------------------------
int CLOSE_CURRENT_RESULT = 1;
int KEEP_CURRENT_RESULT = 2;
int CLOSE_ALL_RESULTS = 3;
int SUCCESS_NO_INFO = -2;
int EXECUTE_FAILED = -3;
int RETURN_GENERATED_KEYS = 1;
int NO_GENERATED_KEYS = 2;
boolean getMoreResults(int current) throws SQLException;
ResultSet getGeneratedKeys() throws SQLException;
int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException;
int executeUpdate(String sql, int columnIndexes[]) throws SQLException;
int executeUpdate(String sql, String columnNames[]) throws SQLException;
boolean execute(String sql, int autoGeneratedKeys) throws SQLException;
boolean execute(String sql, int columnIndexes[]) throws SQLException;
boolean execute(String sql, String columnNames[]) throws SQLException;
int getResultSetHoldability() throws SQLException;
boolean isClosed() throws SQLException;
void setPoolable(boolean poolable)throws SQLException;
boolean isPoolable()throws SQLException;
//--------------------------JDBC 4.1 -----------------------------
//语句所有依赖的结果集都被关闭时
public void closeOnCompletion() throws SQLException;
public boolean isCloseOnCompletion() throws SQLException;
//--------------------------JDBC 4.2 -----------------------------
//增加了对大数据的处理(一般不用)
default long getLargeUpdateCount() throws SQLException {
throw new UnsupportedOperationException("getLargeUpdateCount not implemented");
}
default void setLargeMaxRows(long max) throws SQLException {
throw new UnsupportedOperationException("setLargeMaxRows not implemented");
}
default long getLargeMaxRows() throws SQLException {
return 0;
}
default long[] executeLargeBatch() throws SQLException {
throw new UnsupportedOperationException("executeLargeBatch not implemented");
}
default long executeLargeUpdate(String sql) throws SQLException {
throw new UnsupportedOperationException("executeLargeUpdate not implemented");
}
default long executeLargeUpdate(String sql, int autoGeneratedKeys)
throws SQLException {
throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented");
}
default long executeLargeUpdate(String sql, int columnIndexes[]) throws SQLException {
throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented");
}
default long executeLargeUpdate(String sql, String columnNames[])
throws SQLException {
throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented");
}
}

PreparedStatement

  • PreparedStatement会预编译,会被缓冲,在缓存区中可以发现预编译的命令,虽然会被再次解析,但不会被再次编译,能够有效提高系统性能
  • PreparedStatement能够预防SQL注入攻击
  • PreparedStatement继承了Statement,添加了处理输入参数的方法setXX
  • PreparedStatement定义了execute、executeQuery、addBatch
  • 可变参数的SQL,编译一次,执行多次,效率高;
  • 安全性好,有效防止Sql注入等问题;
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
public interface PreparedStatement extends Statement {
ResultSet executeQuery() throws SQLException;
int executeUpdate() throws SQLException;
void setNull(int parameterIndex, int sqlType) throws SQLException;
void setBoolean(int parameterIndex, boolean x) throws SQLException;
void setByte(int parameterIndex, byte x) throws SQLException;
void setShort(int parameterIndex, short x) throws SQLException;
void setInt(int parameterIndex, int x) throws SQLException;
void setLong(int parameterIndex, long x) throws SQLException;
void setFloat(int parameterIndex, float x) throws SQLException;
void setDouble(int parameterIndex, double x) throws SQLException;
void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException;
void setString(int parameterIndex, String x) throws SQLException;
void setBytes(int parameterIndex, byte x[]) throws SQLException;
void setDate(int parameterIndex, java.sql.Date x)throws SQLException;
void setTime(int parameterIndex, java.sql.Time x)throws SQLException;
void setTimestamp(int parameterIndex, java.sql.Timestamp x)throws SQLException;
void setAsciiStream(int parameterIndex, java.io.InputStream x, int length)throws SQLException;
void setUnicodeStream(int parameterIndex, java.io.InputStream x,int length) throws SQLException;
void setBinaryStream(int parameterIndex, java.io.InputStream x,int length) throws SQLException;
//----------------------------------------------------------------------
void setObject(int parameterIndex, Object x, int targetSqlType)throws SQLException;
void setObject(int parameterIndex, Object x) throws SQLException;
boolean execute() throws SQLException;
//--------------------------JDBC 2.0-----------------------------
void addBatch() throws SQLException;
void setCharacterStream(int parameterIndex,java.io.Reader reader,int length) throws SQLException;
void setRef (int parameterIndex, Ref x) throws SQLException;
void setBlob (int parameterIndex, Blob x) throws SQLException;
void setClob (int parameterIndex, Clob x) throws SQLException;
void setArray (int parameterIndex, Array x) throws SQLException;
ResultSetMetaData getMetaData() throws SQLException;
void setDate(int parameterIndex, java.sql.Date x, Calendar cal)throws SQLException;
void setTime(int parameterIndex, java.sql.Time x, Calendar cal)throws SQLException;
void setTimestamp(int parameterIndex, java.sql.Timestamp x, Calendar cal)throws SQLException;
void setNull (int parameterIndex, int sqlType, String typeName)throws SQLException;
//------------------------- JDBC 3.0 -----------------------------------
void setURL(int parameterIndex, java.net.URL x) throws SQLException;
ParameterMetaData getParameterMetaData() throws SQLException;
//------------------------- JDBC 4.0 -----------------------------------
void setRowId(int parameterIndex, RowId x) throws SQLException;
void setNString(int parameterIndex, String value) throws SQLException;
void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException;
void setNClob(int parameterIndex, NClob value) throws SQLException;
void setClob(int parameterIndex, Reader reader, long length)throws SQLException;
void setBlob(int parameterIndex, InputStream inputStream, long length)throws SQLException;
void setNClob(int parameterIndex, Reader reader, long length)throws SQLException;
void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException;
void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)throws SQLException;
void setAsciiStream(int parameterIndex, java.io.InputStream x, long length)throws SQLException;
void setBinaryStream(int parameterIndex, java.io.InputStream x,long length) throws SQLException;
void setCharacterStream(int parameterIndex,java.io.Reader reader,long length) throws SQLException;
void setAsciiStream(int parameterIndex, java.io.InputStream x)throws SQLException;
void setBinaryStream(int parameterIndex, java.io.InputStream x)throws SQLException;
void setCharacterStream(int parameterIndex,java.io.Reader reader) throws SQLException;
void setNCharacterStream(int parameterIndex, Reader value) throws SQLException;
void setClob(int parameterIndex, Reader reader)throws SQLException;
void setBlob(int parameterIndex, InputStream inputStream)throws SQLException;
void setNClob(int parameterIndex, Reader reader)throws SQLException;
//------------------------- JDBC 4.2 -----------------------------------
default void setObject(int parameterIndex, Object x, SQLType targetSqlType,int scaleOrLength) throws SQLException {
throw new SQLFeatureNotSupportedException("setObject not implemented");
}
default void setObject(int parameterIndex, Object x, SQLType targetSqlType)throws SQLException {
throw new SQLFeatureNotSupportedException("setObject not implemented");
}
default long executeLargeUpdate() throws SQLException {
throw new UnsupportedOperationException("executeLargeUpdate not implemented");
}
}

CallableStatement

  • CallableStatement继承自prepareStatement,实现了存储过程函数调用的方法以及对于输出的处理
  • 扩展了getXX
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
public interface CallableStatement extends PreparedStatement {
void registerOutParameter(int parameterIndex, int sqlType)throws SQLException;
void registerOutParameter(int parameterIndex, int sqlType, int scale)throws SQLException;
boolean wasNull() throws SQLException;
String getString(int parameterIndex) throws SQLException;
boolean getBoolean(int parameterIndex) throws SQLException;
byte getByte(int parameterIndex) throws SQLException;
short getShort(int parameterIndex) throws SQLException;
int getInt(int parameterIndex) throws SQLException;
long getLong(int parameterIndex) throws SQLException;
float getFloat(int parameterIndex) throws SQLException;
double getDouble(int parameterIndex) throws SQLException;
@Deprecated
BigDecimal getBigDecimal(int parameterIndex, int scale)throws SQLException;
byte[] getBytes(int parameterIndex) throws SQLException;
java.sql.Date getDate(int parameterIndex) throws SQLException;
java.sql.Time getTime(int parameterIndex) throws SQLException;
java.sql.Timestamp getTimestamp(int parameterIndex)throws SQLException;
//----------------------------------------------------------------------
Object getObject(int parameterIndex) throws SQLException;
//--------------------------JDBC 2.0-----------------------------
BigDecimal getBigDecimal(int parameterIndex) throws SQLException;
Object getObject(int parameterIndex, java.util.Map<String,Class<?>> map)throws SQLException;
Ref getRef (int parameterIndex) throws SQLException;
Blob getBlob (int parameterIndex) throws SQLException;
Clob getClob (int parameterIndex) throws SQLException;
Array getArray (int parameterIndex) throws SQLException;
java.sql.Date getDate(int parameterIndex, Calendar cal)throws SQLException;
java.sql.Time getTime(int parameterIndex, Calendar cal)throws SQLException;
java.sql.Timestamp getTimestamp(int parameterIndex, Calendar cal)throws SQLException;
void registerOutParameter (int parameterIndex, int sqlType, String typeName)throws SQLException;
//--------------------------JDBC 3.0-----------------------------
void registerOutParameter(String parameterName, int sqlType)throws SQLException;
void registerOutParameter(String parameterName, int sqlType, int scale)throws SQLException;
void registerOutParameter (String parameterName, int sqlType, String typeName)throws SQLException;
java.net.URL getURL(int parameterIndex) throws SQLException;
void setURL(String parameterName, java.net.URL val) throws SQLException;
void setNull(String parameterName, int sqlType) throws SQLException;
void setBoolean(String parameterName, boolean x) throws SQLException;
void setByte(String parameterName, byte x) throws SQLException;
void setShort(String parameterName, short x) throws SQLException;
void setInt(String parameterName, int x) throws SQLException;
void setLong(String parameterName, long x) throws SQLException;
void setFloat(String parameterName, float x) throws SQLException;
void setDouble(String parameterName, double x) throws SQLException;
void setBigDecimal(String parameterName, BigDecimal x) throws SQLException;
void setString(String parameterName, String x) throws SQLException;
void setBytes(String parameterName, byte x[]) throws SQLException;
void setDate(String parameterName, java.sql.Date x)throws SQLException;
void setTime(String parameterName, java.sql.Time x)throws SQLException;
void setTimestamp(String parameterName, java.sql.Timestamp x)throws SQLException;
void setAsciiStream(String parameterName, java.io.InputStream x, int length)throws SQLException;
void setBinaryStream(String parameterName, java.io.InputStream x,int length) throws SQLException;
void setObject(String parameterName, Object x, int targetSqlType, int scale)throws SQLException;
void setObject(String parameterName, Object x, int targetSqlType)throws SQLException;
void setObject(String parameterName, Object x) throws SQLException;
void setCharacterStream(String parameterName,java.io.Reader reader,int length) throws SQLException;
void setDate(String parameterName, java.sql.Date x, Calendar cal)throws SQLException;
void setTime(String parameterName, java.sql.Time x, Calendar cal)throws SQLException;
void setTimestamp(String parameterName, java.sql.Timestamp x, Calendar cal)throws SQLException;
void setNull (String parameterName, int sqlType, String typeName)throws SQLException;
String getString(String parameterName) throws SQLException;
boolean getBoolean(String parameterName) throws SQLException;
byte getByte(String parameterName) throws SQLException;
short getShort(String parameterName) throws SQLException;
int getInt(String parameterName) throws SQLException;
long getLong(String parameterName) throws SQLException;
float getFloat(String parameterName) throws SQLException;
double getDouble(String parameterName) throws SQLException;
byte[] getBytes(String parameterName) throws SQLException;
java.sql.Date getDate(String parameterName) throws SQLException;
java.sql.Time getTime(String parameterName) throws SQLException;
java.sql.Timestamp getTimestamp(String parameterName) throws SQLException;
Object getObject(String parameterName) throws SQLException;
BigDecimal getBigDecimal(String parameterName) throws SQLException;
Object getObject(String parameterName, java.util.Map<String,Class<?>> map)throws SQLException;
Ref getRef (String parameterName) throws SQLException;
Blob getBlob (String parameterName) throws SQLException;
Clob getClob (String parameterName) throws SQLException;
Array getArray (String parameterName) throws SQLException;
java.sql.Date getDate(String parameterName, Calendar cal)throws SQLException;
java.sql.Time getTime(String parameterName, Calendar cal)throws SQLException;
java.sql.Timestamp getTimestamp(String parameterName, Calendar cal)throws SQLException;
java.net.URL getURL(String parameterName) throws SQLException;
//------------------------- JDBC 4.0 -----------------------------------
RowId getRowId(int parameterIndex) throws SQLException;
RowId getRowId(String parameterName) throws SQLException;
void setRowId(String parameterName, RowId x) throws SQLException;
void setNString(String parameterName, String value)throws SQLException;
void setNCharacterStream(String parameterName, Reader value, long length)throws SQLException;
void setNClob(String parameterName, NClob value) throws SQLException;
void setClob(String parameterName, Reader reader, long length)throws SQLException;
void setBlob(String parameterName, InputStream inputStream, long length)throws SQLException;
void setNClob(String parameterName, Reader reader, long length)throws SQLException;
NClob getNClob (int parameterIndex) throws SQLException;
NClob getNClob (String parameterName) throws SQLException;
void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException;
SQLXML getSQLXML(int parameterIndex) throws SQLException;
SQLXML getSQLXML(String parameterName) throws SQLException;
String getNString(int parameterIndex) throws SQLException;
String getNString(String parameterName) throws SQLException;
java.io.Reader getNCharacterStream(int parameterIndex) throws SQLException;
java.io.Reader getNCharacterStream(String parameterName) throws SQLException;
java.io.Reader getCharacterStream(int parameterIndex) throws SQLException;
java.io.Reader getCharacterStream(String parameterName) throws SQLException;
void setBlob (String parameterName, Blob x) throws SQLException;
void setClob (String parameterName, Clob x) throws SQLException;
void setAsciiStream(String parameterName, java.io.InputStream x, long length)throws SQLException;
void setBinaryStream(String parameterName, java.io.InputStream x,long length) throws SQLException;
void setCharacterStream(String parameterName,java.io.Reader reader,long length) throws SQLException;
void setAsciiStream(String parameterName, java.io.InputStream x)throws SQLException;
void setBinaryStream(String parameterName, java.io.InputStream x)throws SQLException;
void setCharacterStream(String parameterName,java.io.Reader reader) throws SQLException;
void setNCharacterStream(String parameterName, Reader value) throws SQLException;
void setClob(String parameterName, Reader reader)throws SQLException;
void setBlob(String parameterName, InputStream inputStream)throws SQLException;
void setNClob(String parameterName, Reader reader)throws SQLException;
//------------------------- JDBC 4.1 -----------------------------------
public <T> T getObject(int parameterIndex, Class<T> type) throws SQLException;
public <T> T getObject(String parameterName, Class<T> type) throws SQLException;
//------------------------- JDBC 4.2 -----------------------------------
default void setObject(String parameterName, Object x, SQLType targetSqlType,int scaleOrLength) throws SQLException {
throw new SQLFeatureNotSupportedException("setObject not implemented");
}
default void setObject(String parameterName, Object x, SQLType targetSqlType)throws SQLException {
throw new SQLFeatureNotSupportedException("setObject not implemented");
}
default void registerOutParameter(int parameterIndex, SQLType sqlType)throws SQLException {
throw new SQLFeatureNotSupportedException("registerOutParameter not implemented");
}
default void registerOutParameter(int parameterIndex, SQLType sqlType,int scale) throws SQLException {
throw new SQLFeatureNotSupportedException("registerOutParameter not implemented");
}
default void registerOutParameter (int parameterIndex, SQLType sqlType,String typeName) throws SQLException {
throw new SQLFeatureNotSupportedException("registerOutParameter not implemented");
}
default void registerOutParameter(String parameterName, SQLType sqlType)throws SQLException {
throw new SQLFeatureNotSupportedException("registerOutParameter not implemented");
}
default void registerOutParameter(String parameterName, SQLType sqlType,int scale) throws SQLException {
throw new SQLFeatureNotSupportedException("registerOutParameter not implemented");
}
default void registerOutParameter (String parameterName, SQLType sqlType,String typeName) throws SQLException {
throw new SQLFeatureNotSupportedException("registerOutParameter not implemented");
}
}

继承关系 CallableStatement -> PreparedStatement -> Statement

Connection

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
public interface Connection  extends Wrapper, AutoCloseable {
Statement createStatement() throws SQLException;
PreparedStatement prepareStatement(String sql)throws SQLException;
CallableStatement prepareCall(String sql) throws SQLException;
String nativeSQL(String sql) throws SQLException;
void setAutoCommit(boolean autoCommit) throws SQLException;
boolean getAutoCommit() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
boolean isClosed() throws SQLException;
//======================================================================
// Advanced features:
DatabaseMetaData getMetaData() throws SQLException;
void setReadOnly(boolean readOnly) throws SQLException;
boolean isReadOnly() throws SQLException;
void setCatalog(String catalog) throws SQLException;
String getCatalog() throws SQLException;
int TRANSACTION_NONE = 0;
int TRANSACTION_READ_UNCOMMITTED = 1;
int TRANSACTION_READ_COMMITTED = 2;
int TRANSACTION_REPEATABLE_READ = 4;
int TRANSACTION_SERIALIZABLE = 8;
void setTransactionIsolation(int level) throws SQLException;
int getTransactionIsolation() throws SQLException;
SQLWarning getWarnings() throws SQLException;
void clearWarnings() throws SQLException;
//--------------------------JDBC 2.0-----------------------------
Statement createStatement(int resultSetType, int resultSetConcurrency)throws SQLException;
PreparedStatement prepareStatement(String sql, int resultSetType,int resultSetConcurrency)throws SQLException;
CallableStatement prepareCall(String sql, int resultSetType,int resultSetConcurrency) throws SQLException;
java.util.Map<String,Class<?>> getTypeMap() throws SQLException;
void setTypeMap(java.util.Map<String,Class<?>> map) throws SQLException;
//--------------------------JDBC 3.0-----------------------------
void setHoldability(int holdability) throws SQLException;
int getHoldability() throws SQLException;
Savepoint setSavepoint() throws SQLException;
Savepoint setSavepoint(String name) throws SQLException;
void rollback(Savepoint savepoint) throws SQLException;
void releaseSavepoint(Savepoint savepoint) throws SQLException;
Statement createStatement(int resultSetType, int resultSetConcurrency,int resultSetHoldability) throws SQLException;
PreparedStatement prepareStatement(String sql, int resultSetType,int resultSetConcurrency, int resultSetHoldability)throws SQLException;
CallableStatement prepareCall(String sql, int resultSetType,int resultSetConcurrency,int resultSetHoldability) throws SQLException;
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)throws SQLException;
PreparedStatement prepareStatement(String sql, int columnIndexes[])throws SQLException;
PreparedStatement prepareStatement(String sql, String columnNames[])throws SQLException;
Clob createClob() throws SQLException;
Blob createBlob() throws SQLException;
NClob createNClob() throws SQLException;
SQLXML createSQLXML() throws SQLException;
boolean isValid(int timeout) throws SQLException;
void setClientInfo(String name, String value)throws SQLClientInfoException;
void setClientInfo(Properties properties)throws SQLClientInfoException;
String getClientInfo(String name)throws SQLException;
Properties getClientInfo()throws SQLException;
Array createArrayOf(String typeName, Object[] elements) throws SQLException;
Struct createStruct(String typeName, Object[] attributes) throws SQLException;
//--------------------------JDBC 4.1 -----------------------------
void setSchema(String schema) throws SQLException;
String getSchema() throws SQLException;
void abort(Executor executor) throws SQLException;
void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException;
int getNetworkTimeout() throws SQLException;
}

ResultSet和PreparedStatement参数绑定的下表 都是从1开始

参考文档

https://www.cnblogs.com/noteless/p/10307273.html

数据结构分类

线性结构

元素之间存在一对一的关系,线性结构按照存储的方式不同可以分为顺序结构和链式结构,如:数组、链表、队列、栈。

非线性结构

如:二维数组、多维数组、树结构、图结构

【数据结构】稀疏数组

普通存储(二维数组)

  • 第一行存储原始数据总行数,总列数,总的非0数据个数
  • 接下来每一行都存储非0数所在行,所在列,和具体值
  • 转换步骤:首先要获取数据的总行数 -> 定义数组 -> 填值

字符串匹配分类

BF算法、BM算法、KMP算法的。参考:https://baijiahao.baidu.com/s?id=1659735837100760934&wfr=spider&for=pc

队列

  • 先进先出 数组、链 。ArrayBlockingQueue,LinkedBlockingQueue,PriorityQueue
  • BlockQueue 接口方法
Throws exception Special value Blocks Times out
insert add offer put offer
remove remove poll take pull
examine element peek

链表

单向链表、双向链表,环形链表

约瑟夫环(丢手帕)

单项环形链表

先进后出

应用场景

  • 子程序调用(栈帧)
  • 处理递归调用
  • 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)
  • 二叉树遍历
  • 图形深度优先(depth-first)

Stack

前缀表达式(波兰表达式)、中缀表达式、后缀表达式(逆波兰表达式)

前缀表达式

从右至左扫描表

排序算法

将一组数据,依据指定的顺序排列

内部排序 所有数据都加载到内存中进行排序

  • 插入排序(直接插入排序、希尔排序)
  • 选择排序(简单选择排序、堆排序)
  • 交换排序(冒泡、快速排序)
  • 归并排序
  • +基数排序

外部排序 数据量过大,无法全部加载到内存中,需要借助外部存储进行排序

算法时间复杂度

事后统计法

这种方法可行,但是有两个问题,一是要想对设计算法的运行性能进行评测,需要实际运行该程序;二是所得事件的统计量依赖于计算机硬件软件等环境因素,这种方式,要在同一台计算机的相同状态下运行,才能比较哪个算法速度更快。

事前估算的方法

通过分析某个算法的事件复杂度来判断哪个算法更优

一个算法花费的时间与算法中语句执行的次数成正比,哪个算法执行的次数越多,它花费的时间就越多,一个算法中语句执行次数称为语句频度或时间频度

分治算法

分而治之,把一个复杂问题分解为简单问题,多用递归解决。经典问题,汉诺塔问题

动态规划算法

  • 算法的核心思想:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法
  • 动态规划算法与分支算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后再从这些子问题的解中得到原问题的解
  • 与分支算法不同的是,适用于动态规划求解的问题,经分解得到子问题往往不是相互独立的(既下一个字节阶段的求解是建立在上一个子阶段求解的基础上进行进一步求解)
  • 动态规划可以通过填表的方式逐步推进,得到最优解
  • 背包问题 01背包、完全背包

贪心算法

  • 在问题进行求解时,在每一步的选择中都采取最好或者最优的选择,从而希望能够导致结果时最好或者最优的算法
  • 贪心算法所得到的结果不一定时最优的结构,但是都是相对近似最优解的结果
  • 贪心算法解决集合覆盖问题

1、遍历所有的广播电台,找到一个覆盖了最多未覆盖的地区的电台(此电台可能包含一些已覆盖的地区)
2、将这个电台加入到一个集合中,想办法把该电台覆盖的地区在下一次比较时去掉
3、重复第一步直到覆盖了所有的地区

红黑树

二叉查找树+平衡二叉树(大致平衡的)

核心性质

从根节点到任意叶子节点最长的路径不大于最短路径的二倍,在插入和删除操作中核心性质可能不再满足,所以在插入删除中要进行判断是否满足,但是直接判断是否满足核心性质麻烦,就用了五条容易判断的性质进行等价替换。

性质

  • 根节点是黑色的
  • 节点非黑即红
  • 不每条路径上不能有连续两个红色节点
  • 从任意节点到叶子节点黑节点数量相同
  • 叶子节点都是黑色的

插入过程

1.如果插入节点的父节点不存在就将颜色改为黑色。(因为这个节点就是根节点)
2.如果插入的节点的父节点是黑色,则ok,直接return。
3.如果插入的节点的父亲节点和叔叔节点是红色,则变化父叔节点为黑色,再把祖父节点变为红色,然后将祖父节点作为node,从case1开始判断。
4.(1)父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的右子节点而父节点P又是其父节点的左子节点。则父进行左旋,然后执行case5.
(2)父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的左子节点而父节点P又是其父节点的右子节点。
  则父进行右旋,然后执行case5.
5.父变黑,祖父变红
(1)父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的右子节点而父节点P又是其父节点的右子节点。
则祖父进行左旋
(2)父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的左子节点而父节点P又是其父节点的左子节点。
则祖父进行右旋
左旋就是:逆时针
右旋就是:顺时针

删除操作六条:形式也是六个函数,if-else格式的。
1.删除的是根,直接删。

红黑树和avl(二叉平衡树)的比较

  1. 如果插入一个node引起了树的不平衡,AVL和RB-Tree(红黑树)都是最多只需要2次旋转操作,即两者都是O(1);
    但是在删除node引起树的不平衡时,最坏情况下,AVL需要维护从被删node到root这条路径上所有node的平衡性,因此需要旋转的量级O(logN),而RB-Tree最多只需3次(因为不需要严格的平衡,从根到叶子的最长的可能路径不多于最短的可能路径的两倍长)旋转以及修改节点的颜色,只需要O(1)的复杂度。
  2. 其次,AVL的结构相较RB-Tree来说更为平衡,在插入和删除node更容易引起Tree的unbalance,因此在大量数据需要插入或者删除时,AVL需要rebalance的频率会更高。因此,RB-Tree在需要大量插入和删除node的场景下,效率更高。自然,由于AVL高度平衡,因此AVL的search效率更高。
    红黑树实际应用:
    IO多路复用epoll的实现采用红黑树组织管理sockfd,以支持快速的增删改查.
    ngnix中,用红黑树管理timer,因为红黑树是有序的,可以很快的得到距离当前最小的定时器.
    java中TreeMap,jdk1.8的hashmap的实现.

B+树

B+ 树是一种树数据结构,是一个n叉排序树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上孩子节点的节点。
B+树是对B树的一种变形树,它与B树的差异在于:
有k个子结点的结点必然有k个关键码;
非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录,便于区间查找和遍历。
B+ 树的优点在于:

由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。
数据存放的更加紧密,具有更好的空间局部性。
因此访问叶子节点上关联的数据也具有更好的缓存命中率。
B+树的叶子结点都是相链的,因此对整棵树的便利只需要一次线性遍历叶子结点即可。
而且由于数据顺序排列并且相连,所以便于区间查找和搜索。
而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。
但是B树也有优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。下面是B 树和B+树的区别图:

b+树的应用场景:

B/B+树是为了磁盘或其它存储设备而设计的一种平衡多路查找树(相对于二叉,B树每个内节点有多个分支),与红黑树相比,在相同的的节点的情况下,
一颗B/B+树的高度远远小于红黑树的高度(在下面B/B+树的性能分析中会提到).B/B+树上操作的时间通常由存取磁盘的时间和CPU计算时间这两部分构成,而CPU的速度非常快,
所以B树的操作效率取决于访问磁盘的次数,关键字总数相同的情况下B树的高度越小,磁盘I/O所花的时间越少.
二叉查找树的结构不适合数据库,因为它的查找效率与层数相关。越处在下层的数据,就需要越多次比较。对于数据库来说,每进入一层,就要从硬盘读取一次数据,
这非常致命,因为硬盘的读取时间远远大于数据处理时间,数据库读取硬盘的次数越少越好。这种数据结构,非常有利于减少读取硬盘的次数。假定一个节点可以容纳100个值,
那么3层的B树可以容纳100万个数据,如果换成二叉查找树,则需要20层!假定操作系统一次读取一个节点,并且根节点保留在内存中,那么B树在100万个数据中查找目标值,
只需要读取两次硬盘。

图的遍历

深度优先 Depth First Search 每次都在访问当前节点的第一个邻接点 纵向挖掘深入,递归的过程

1、访问初始节点v,并标记该节点已经访问
2、查找节点v的第一个邻结点w
3、若w不存在,则返回第一步,从v的下一个节点继续访问
4、若w未被访问,对w进行深度访问
5、查找v的邻结点的下一个邻结点

广度优先

二叉树:
前序排序:根->左->右
中 左->根->右
后 左->右-> 根
左永远在前, 根 前 中 后

深度优先,广度优先

数据结构:
线性结构 元素之间存在一对一的线性关系
顺讯存储
链式存储(链表)
数组、队列、链表、

递归

各种数学问题,八皇后问题,汉诺塔、阶乘、迷宫、球和篮子

各种算法中也会使用到递归,快排序,归并排序、二分查找、分治算法
将用栈解决的问题 –> 递归代码比较简洁

注意:
执行一个方法时,就创建一个栈空间(栈帧)
方法的局部变量是独立的,不会相互影响
如果方法中使用的是引用类型的变量,就会共享改类型的数据
递归必须向退出递归条件逼近,否则就会无限循环

二叉树:每个节点最多有两个子节点(左节点,右节点)

满二叉树:所有叶子节点都在最后一层 且节点数为2^n-1,所有节点都有两个子节点
完全二叉树:所有叶子节点在最后一层或者倒数第二层,最后一层左边连续,倒数第二层 右边连续

二叉树遍历:
前:根 -> 左 -> 右 递归
中:左 -> 根 -> 右
后:左 -> 右 -> 根

所有遍历都是从根开始

顺序存储二叉树

二叉树的数据以数组的方式存放 (完全二叉树)

n个元素的左节点 2n+1
n个元素的右节点 2n+2
n个元素的父节点 (n-1)/2

线索话二叉树

堆排序

大顶堆 根> 左右

小顶堆 根 < 左右

基本概念

  • Producer:生产者,负责创建消息,然后将其投递到Kafka中
  • Consumer:消费者,连接到Kafka上并接收消息,进而进行相应的业务逻辑处理
  • Broker:服务代理节点。对于Kafka而言,Broker可以简单地看作一个独立的Kafka服务节点或Kafka服务实例,一个或多个Broker组成了一个Kafka集群
  • Topic:主题,消息归类(逻辑上)
  • Partition:分区,消息归类(物理上)
  • ISR:与leader副本保持一定程度同步的副本(包括Leader)组成ISR(In-Sync Replicas)
  • OSR:与leader副本同步滞后过多的副本(不包括leader)副本,组成OSR(Out-Sync Replicas)
  • AR=ISR+OSR
  • HW:High Watermark的缩写,俗称高水位,它标识了一个特定的消息偏移量(offset),消费者只能拉取到这个offset之前的消息
  • LEO:Log End Offset的缩写,它标识当前日志文件中下一条待写入消息的offse,所有副本中最小LEO即为HW

Partition

  • 一个主题对应多个分区,不同分区可能分布在不同的Broker上,增加分区可以增加kafka水平扩展能力,一个分区也只能被同一个消费者组的一个消费者消费
  • 分区可以有多个副本,一主多从,副本默认不提供服务,做容灾使用
  • 同一主题下不同分区的数据不同(hash散列)
  • 单个分区内消息有序
  • 分区在存储层面可以看作一个可追加的日志(Log)文件,消息在被追加到分区日志文件的时候都会分配一个特定的偏移量(offset)

常用配置项

Producer配置项

官方文档

配置项 说明
key.serializer
value.serializer
acks
bootstrap.servers
buffer.memory RecordAccumulator 消息累加器缓存消息的大小,默认32M如果生产者发送消息的速度超过发送到服务器的速度,则会导致生产者空间不足,这个时候KafkaProducer的send()方法调用要么被阻塞,要么抛出异常,这个取决于参数max.block.ms的配置,此参数的默认值为60000,即60秒
max.block.ms 消息累加器满后发送消息最长阻塞时间
compression.type
batch.size ProducerBatch 的大小,实际上是BufferPool来管理的
retries
ssl.key.password
ssl.keystore.certificate.chain
ssl.keystore.key
ssl.keystore.location
ssl.keystore.password
ssl.truststore.certificates
client.dns.lookup
client.id
connections.max.idle.ms
delivery.timeout.ms
linger.ms
max.request.size

| partitioner.class | |
| request.timeout.ms | |
| sasl.client.callback.handler.class | |
| sasl.jaas.config | |
| sasl.kerberos.service.name | |
| sasl.login.callback.handler.class | |
| sasl.login.class | |
| sasl.mechanism | |
| security.protocol | |
| send.buffer.bytes | |
| receive.buffer.bytes | |

生产者客户端架构

https://img-blog.csdnimg.cn/20200503133843165.png

核心对象

KafkaProducer

ProducerRecord

分区器
Partitioner
Serialize
Interceptor
KafkaProducer中一般会发生两种类型的异常:可重试的异常和不可重试的异常。常见的可重试异常有:NetworkException、LeaderNotAvailableException、UnknownTopicOrPartitionException、NotEnoughReplicasException、NotCoordinatorException 等。比如NetworkException 表示网络异常,这个有可能是由于网络瞬时故障而导致的异常,可以通过重试解决;又比如LeaderNotAvailableException表示分区的leader副本不可用,这个异常通常发生在leader副本下线而新的 leader 副本选举完成之前,重试之后可以重新恢复。不可重试的异常,比如 1.4 节中提及的RecordTooLargeException异常,暗示了所发送的消息太大,KafkaProducer对此不会进行任何重试,直接抛出异常。对于可重试的异常,如果配置了 retries 参数,那么只要在规定的重试次数内自行恢复了,就不会抛出异常。retries参数的默认值为0,配置方式参考如下

默认的分区器会对 key 进行哈希(采用MurmurHash2算法,具备高运算性能及低碰撞率),最终根据得到的哈希值来计算分区号,拥有相同key的消息会被写入同一个分区。如果key为null,那么消息将会以轮询的方式发往主题内的各个可用分区

如果 key 不为 null,那么计算得到的分区号会是所有分区中的任意一个;如果 key为null,那么计算得到的分区号仅为可用分区中的任意一个,注意两者之间的差别

发送消息主要有三种模式
发后即忘(fire-and-forget)
同步(sync)
异步(async)

broker配置项

  • auto.create.topics.enable:自动创建主题,默认true,生产环境不建议开启
  • num.partitions:默认分区数量
  • default.replication.factor:默认副本数量

listeners参数说明

表示broker监听客户端连接的地址列表,即为客户端要连接broker的入口地址列表,配置格式为 protocol1://hostname1:port1,protocol2://hostname2:port2

  • protocol代表协议类型,Kafka当前支持的协议类型有PLAINTEXT、SSL、SASL_SSL等,如果未开启安全认证,则使用简单的PLAINTEXT即可
  • hostname代表主机名,port代表服务端口,此参数的默认值为 null。比如此参数配置为 PLAINTEXT://198.162.0.2:9092,如果有多个地址,则中间以逗号隔开

advertised.listeners参数说明

作用和listeners类似,默认值也为 null。不过 advertised.listeners 主要用于 IaaS(Infrastructure as a Service)环境,比如公有云上的机器通常配备有多块网卡,即包含私网网卡和公网网卡,对于这种情况而言,可以设置advertised.listeners参数绑定公网IP供外部客户端使用,而配置listeners参数来绑定私网IP地址供broker间通信使用

常用命令

创建主题

1
./bin/kafka-topics.sh --create --zookeeper 127.0.0.1:2181 --replication-factor 2 --partitions 3 --topic test

查看主题

1
./bin/kafka-topics.sh --list --zookeeper 127.0.0.1:2181

查看主题详情

1
./bin/kafka-topics.sh --list --zookeeper 127.0.0.1:2181 --describe --topic test

删除主题

1
./bin/kafka-topics.sh --delete --zookeeper 127.0.0.1:2181 --topic test

发送消息

1
./bin/kafka-console-producer.sh --broker-list 127.0.0.1:9092 --topic test

消费消息

1
2
./bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic test --from-beginning
./bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic test

查看消费者

1
./bin/kafka-consumer-groups.sh --bootstrap-server 127.0.0.1:9092 --list

查看正在消费的topic(消息积压)

1
./bin/kafka-consumer-groups.sh --bootstrap-server 127.0.0.1:9092 --describe --group console-consumer-63307 

查看topic某分区偏移量最值

1
./bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic daShuJuPushDataTopic -time -1

创建主题约束

kafka-topics.sh脚本在创建主题时还会检测是否包含“.”或“_”字符。为什么要检测这两个字符呢?因为在Kafka的内部做埋点时会根据主题的名称来命名metrics的名称,并且会将点号“.”改成下画线“_”。假设遇到一个名称为“topic.1_2”的主题,还有一个名称为“topic_1.2”的主题,那么最后的metrics的名称都会为“topic_1_2”,这样就发生了名称冲突。举例如下,首先创建一个以“topic.1_2”为名称的主题,提示 WARNING 警告,之后再创建“topic.1_2”时发生InvalidTopicException异常

kafka机架感知(broker.rack)

Kafka从0.10.x版本开始支持指定broker的机架信息(机架的名称)。如果指定了机架信息,则在分区副本分配时会尽可能地让分区副本分配到不同的机架上。指定机架信息是通过broker端参数broker.rack来配置的,比如配置当前broker所在的机架为“RACK1

本地启动kafka

1
D:\kafka_2.13-2.6.0\bin\windows\kafka-server-start.bat D:\kafka_2.13-2.6.0\config\server.properties

linux 常用快捷键

1
2
3
4
5
6
7
8
9
10
11
12
13
Ctrl + a : 将光标跳转到当前命令的行首(ahead)
Ctrl + e :将光标跳转到当前命令的行尾(end)
Ctrl + w :按照空格删除光标之前的命令(word)
Ctrl + c :终止当前的命令(cancel)
Ctrl + l :清屏(命令clear的功能)
Ctrl + r :查找执行的最近的一条命令(包含查找的字母)
Ctrl + d :退出当前的bash(只退出一个)exit logout(退出当前登陆的用户)
Ctrl + z :把程序放在后台运行(windows上QQ最小化)
Ctrl + k :删除当前光标到行尾的所有内容
Ctrl + u :删除当前光标到行首的所有内容
Ctrl + s :锁定当前命令行
Ctrl + q :解锁当前命令行
Ctrl + 左右:快速移动光标

idea 快捷键

Ctrl + Shift + F12 :全屏
Ctrl + Shift + V :从历史命令中粘贴
Ctrl + Shift + ALT + V :无格式粘贴
Ctrl + Alt + M : 将选中代码生成方法

subline快捷键

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
# 选择类快捷键 
Ctrl + D : 选中光标所占的文本,继续操作则会选中下一个相同的文本
Alt + F3 : 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑 举个栗子:快速选中并更改所有相同的变量名、函数名等
Ctrl + L : 选中整行,继续操作则继续选择下一行,效果和 Shift+↓ 效果一样
Ctrl + M : 光标移动至括号内结束或开始的位置
Ctrl + Shift + L : 先选中多行,再按下快捷键,会在每行行尾插入光标,即可同时编辑这些行
Ctrl + Shift + M : 选择括号内的内容(继续选择父括号) 举个栗子:快速选中删除函数中的代码,重写函数体代码或重写括号内里的内容
Ctrl + Enter : 在下一行插入新行 举个栗子:即使光标不在行尾,也能快速向下插入一行
Ctrl + Shift + Enter : 在上一行插入新行 举个栗子:即使光标不在行首,也能快速向上插入一行
Ctrl + Shift + [ : 选中代码,按下快捷键,折叠代码
Ctrl + Shift + ] : 选中代码,按下快捷键,展开代码
Ctrl + K + 0 : 展开所有折叠代码
Ctrl + ← : 向左单位性地移动光标,快速移动光标
Ctrl + → : 向右单位性地移动光标,快速移动光标
shift + ↑ : 向上选中多行
shift + ↓ : 向下选中多行
Shift + ← : 向左选中文本
Shift + → : 向右选中文本
Ctrl + Shift + ← : 向左单位性地选中文本
Ctrl + Shift + → :向右单位性地选中文本
Ctrl + Shift + ↑ : 将光标所在行和上一行代码互换(将光标所在行插入到上一行之前)
Ctrl + Shift + ↓ : 将光标所在行和下一行代码互换(将光标所在行插入到下一行之后)
Ctrl + Alt + ↑ : 向上添加多行光标,可同时编辑多行
Ctrl + Alt + ↓ : 向下添加多行光标,可同时编辑多行
# 编辑快捷键
Ctrl + J :合并选中的多行代码为一行,举个栗子:将多行格式的CSS属性合并为一行
Ctrl + Shift+D 复制光标所在整行,插入到下一行
Shift + Tab 向左缩进
Ctrl + K : 从光标处开始删除代码至行尾
Ctrl + Shift+K : 删除整行
Ctrl + / : 注释单行
Ctrl + Shift + / : 注释多
Ctrl + K+U : 转换大写
Ctrl + K+L : 转换小写
Ctrl + Z : 撤销
Ctrl + Y : 恢复撤销
Ctrl + T 左右字母互换
F6 单词检测拼写

常用命令

script
1
2
3
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
df -l -P | awk '{if(NR>1){print $6}}' |xargs -i find {} -name "*.txt"
openssl s_client -servername www.baidu.com xx -connect www.baidu.com:443

简介

maven 打包自动备份源码插件

源码地址:https://github.com/dennis120338/auto-back-maven-plugin.git

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<build>
<plugins>
<!-- 打包时自动备份源代码 -->
<plugin>
<groupId>com.laohand</groupId>
<artifactId>auto-back-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<!--备份目录,默认 /data0/back -->
<path>/data0/test</path>
</configuration>
</plugin>
</plugins>
</build>

code-generator

每个程序员都应该要有自己的代码生成器

简介

  • code-generator是一个适用于Spring、Spring Boot、Spring Cloud通用代码生成的框架
  • code-generator库非常小,并且无第三方依赖,可以放心引入项目中而不会同其他包冲突
  • 通过该工具可以通过模块生成通用代码,极大提高生产效率
  • 通过自定义模板,可以生成php、python、javascript等任何语言通用代码

安装方式

maven安装

1
2
3
4
5
<dependency>
<groupId>com.laohand</groupId>
<artifactId>code-generator</artifactId>
<version>1.0.0</version>
</dependency>

Gradle 安装

1
implementation 'com.laohand:code-generator:1.0.0'

使用方式

新建类CodeGen,示例代码如下便可生成一个模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.foundao;
import com.laohand.generator.CodeGenerator;
import java.io.IOException;
public class CodeGen {
public static void main(String[] args) throws IOException {
String sql = "CREATE TABLE 'user' (\\n\" +\n" +
" \" 'user_id' int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\\n\" +\n" +
" \" 'username' varchar(255) NOT NULL COMMENT '用户名',\\n\" +\n" +
" \" 'addtime' datetime NOT NULL COMMENT '创建时间',\\n\" +\n" +
" \" PRIMARY KEY ('user_id')\\n\" +\n" +
" \") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息'\\n\" +\n" +
" \" ";
CodeGenerator.gen(sql, "com.laohand", "copyright", "F:\\github\\foundao\\geesee_copyright\\src\\main\\java\\com\\foundao");
}
}

执行代码自动生成代码如下:
Code Generator preview
内置模板以Spring Boot + TK mybatis框架为基础,生成controller、service、mapper、pojo等文件,并内置了常见的增删改查操作。
当然,该模板仅适用于作者,可能并不适合大多数开发者。后面通过简单分析代码演示如何自定义模板。

代码简析

CodeGenerator.gen()方法存在多个重构,但是最终都会调用以下方法

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
/**
* 生成文件
*
* @param sql 创建数据表文件
* @param packageName 模块基本包命,生成的模块将会放在该包下面
* @param moduleName 模块名称
* @param savePath 模块保存路径,需要传绝地路径
* @param templateSource 模板字符串内容
* @throws IOException
*/
public static void gen(String sql, String packageName, String moduleName, String savePath, TemplateSource templateSource, Map<String, String> userReplace) throws IOException {
ClassInfo classInfo = TableParseUtil.parseSql(sql);
classInfo.setPackageName(packageName);
classInfo.setModuleName(moduleName);
classInfo.setBaseSavePath(savePath);
System.out.println("【INFO】classInfo => " + classInfo.toString());
createFile(classInfo, "controller", classInfo.getClassName() + "Controller.java", templateSource.getControllerTemplate(), userReplace);
createFile(classInfo, "pojo", classInfo.getClassName() + ".java", templateSource.getPojoTemplate(), userReplace);
createFile(classInfo, "service" + File.separator + "impl", classInfo.getClassName() + "ServiceImpl.java", templateSource.getServiceImplTemplate(), userReplace);
createFile(classInfo, "service", classInfo.getClassName() + "Service.java", templateSource.getServiceTemplate(), userReplace);
createFile(classInfo, "mapper", classInfo.getClassName() + "Mapper.java", templateSource.getMapperTemplate(), userReplace);
createFile(classInfo, "mapper", classInfo.getClassName() + "SqlBuilder.java", templateSource.getSqlBuilderTemplate(), userReplace);
}

/**
* 根据模板创建并替换文件
*
* @param classInfo
* @param path 文件存放相对于模块的路径
* @param fileName 保存文件名称
* @param tpl 模板内容
* @param userReplace 用户自定义需要替换的内容
* @throws IOException
*/
public static void createFile(ClassInfo classInfo, String path, String fileName, String tpl, Map<String, String> userReplace) throws IOException {
if (tpl == null | "".equals(tpl)) {
return;
}
String saveFileName = classInfo.getBaseSavePath() + File.separator + classInfo.getModuleName() + File.separator + path + File.separator + fileName;
tpl = tpl.replaceAll("CLASS_NAME_UPPER", classInfo.getClassName());
tpl = tpl.replaceAll("CLASS_NAME_LOWER", classInfo.getClassNameLowerFirst());
tpl = tpl.replaceAll("TABLE_NAME", classInfo.getTableName());
tpl = tpl.replaceAll("TABLE_COMMENT", classInfo.getTableName());
tpl = tpl.replaceAll("PACKAGE", classInfo.getPackageName() + "." + classInfo.getModuleName());
//用户自定义变量替换
if (userReplace != null) {
for (Map.Entry<String, String> entry : userReplace.entrySet()) {
tpl = tpl.replaceAll(entry.getKey(), entry.getValue());
}
}
//以下代码用于替换pojo对象
StringBuilder stringBuffer = new StringBuilder();
for (Column column : classInfo.getFieldList()) {
StringBuilder row = new StringBuilder();
if (column.getFieldComment() != null && !"".equals(column.getFieldComment())) {
row.append(" /**\n" + " * ").append(column.getFieldComment()).append("\n").append(" */\n");
}
String javaFieldName = StringUtil.lowerCaseFirst(StringUtil.underlineToCamelCase(column.getFieldName()));
if (!column.getFieldName().equals(javaFieldName)) {
row.append(" @Column(name = \"").append(column.getFieldName()).append("\")\n");
}
row.append(" private ").append(dbTypeToJava(column.getFieldType())).append(" ").append(javaFieldName).append(";\n");
stringBuffer.append(row);
}
tpl = tpl.replaceAll("POJO_FIELD", stringBuffer.toString());
writeToFile(saveFileName, tpl);
}

替换步骤

  • 解析sql文件内容成为classInfo对象,并将替换所需必要信息设置到classInfo中
  • 调用createFile方法生成文件
  • 调用createFile生成文件是会将模板内的内置变量替换为真实值,模板变量如下:
    • CLASS_NAME_UPPER:pojo文件名称,首字母大写
    • CLASS_NAME_LOWER:pojo文件名称,首字母小写
    • TABLE_NAME:mysql表名称
    • TABLE_COMMENT:mysql表注释
    • PACKAGE:基本包名
    • POJO_FIELD:pojo字段
  • 可以将一些其他自定义变量及替换值放入 userReplace中,在createFile时进行替换
  • 最后将替换好后的内容写入文件中

自定义模板

其实替换原理及代码都很简单,读者简单看看源代码就能明白,这里简单说明一下

方法一实现TemplateSource接口

TemplateSource 接口代码如下:

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
public interface TemplateSource {
/**
* 控制器模板
*
* @return
*/
String getControllerTemplate();

/**
* pojo模板
*
* @return
*/
String getPojoTemplate();

/**
* service接口模板
*
* @return
*/
String getServiceTemplate();

/**
* service实现模板
*
* @return
*/
String getServiceImplTemplate();

/**
* mapper模板
*
* @return
*/
String getMapperTemplate();


/**
* sql生成器模板
*
* @return
*/
String getSqlBuilderTemplate();
}

操作步骤

  • 将标准代码中需要替换的地方替换成模板变量(CLASS_NAME_UPPER、CLASS_NAME_LOWER等)并形成模板
  • 实现TemplateSource接口,在接口实现中返回模板字符串
  • 调用CodeGenerator.gen方法时传入自定义templateSource对象(第五个参数)
    1
    public static void gen(String sql, String packageName, String moduleName, String savePath, TemplateSource templateSource, Map<String, String> userReplace){}

方法二用户自己实现gen方法

实现gen方法逻辑并调用createFile替换,该方法可用于生成任一语言代码,一般用方法一既可

关键名词

image镜像

Docker Images是一个只读模板,用来运行Docker容器

docker container容器

Docker用容器来运行应用,负责应用程序的运行,包括操作系统、用户添加的文件以及元数据。容器是从镜像创建出来的实例(好有面向对象的感觉,类和对象),它可以被启动、开始、停止和删除。

仓库

存放镜像的文件的场所。比如最大的公开仓库是Docker Hub

docker 组件与元素:

  • Docker Client 是用户界面,它支持用户与Docker Daemon之间通信。
  • Docker Daemon运行于主机上,处理服务请求。
  • Docker Index是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份。

    docker安装

    1
    curl -sSL https://get.daocloud.io/docker | sh

    镜像仓库管理命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub eg:docker login -u 用户名 -p 密码
    docker login [OPTIONS] [SERVER]
    # 登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
    docker logout [OPTIONS] [SERVER]
    # 在镜像仓库中搜索镜像 eg:docker search 10 java
    docker search [OPTIONS] TERM
    # 从镜像仓库中拉取或者更新指定镜像 eg:docker pull java
    docker pull [OPTIONS] NAME[:TAG|@DIGEST]
    # 推将本地的镜像上传到镜像仓库,要先登陆到镜像仓库 eg:docker push myapache:v1
    docker push [OPTIONS] NAME[:TAG]

    docker镜像管理命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 列出所有镜像,同 docker image ls,docker image ls -a 列出所有镜像,包括中间镜像
    docker images [OPTIONS] [REPOSITORY[:TAG]]
    # 删除镜像,同 docker image rm IMAGE
    docker rmi [OPTIONS] IMAGE [IMAGE...]
    # 从tar文件中载入镜像 eg:docker load < busybox.tar.gz
    docker load
    # 保存镜像为tar文件 eg:docker save -o my_ubuntu_v3.tar runoob/ubuntu:v3
    docker save [OPTIONS] IMAGE [IMAGE...]
    # docker tag : 标记本地镜像,将其归入某一仓库,eg: docker tag ubuntu:15.10 runoob/ubuntu:v3
    docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
    # 删除 所有未被 tag 标记和未被容器使用的镜像
    docker image prune
    # 删除 所有未被容器使用的镜像
    docker image prune -a
    # 删除 所有停止运行的容器
    docker container prune
    # 使用 Dockerfile 创建镜像 eg:docker build --rm=true -t runoob/ubuntu:v1 . --rm=true表示构建成功后,移除所有中间容器 --no-cache=false表示在构建过程中不使用缓存
    docker build [OPTIONS] PATH | URL | -
    # 查看指定镜像的创建历史 eg:docker history runoob/ubuntu:v3
    docker history [OPTIONS] IMAGE

    其他命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 显示 Docker 系统信息,包括镜像和容器数
    docker info [OPTIONS]
    # 显示 Docker 版本信息
    docker version [OPTIONS]
    # 从容器创建一个新的镜像 eg:docker commit -a "runoob.com" -m "my apache" a404c6c174a2 mymysql:v1
    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
    # 用于容器与主机之间的数据拷贝 eg:docker cp /www 96f7f14e99ab:/www/,docker cp 96f7f14e99ab:/www /tmp/
    docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
    # 检查容器里文件结构的更改
    docker diff [OPTIONS] CONTAINER
    # Show docker disk usage
    docker system df
    # Display system-wide information
    docker system info

    容器操作命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # 列出容器 
    docker ps [OPTIONS]
    # 获取容器/镜像的元数据 eg:inspect mysql:5.6
    docker inspect [OPTIONS] NAME|ID [NAME|ID...]
    # 查看容器中运行的进程信息,支持 ps 命令参数 eg:docker top mysql
    docker top [OPTIONS] CONTAINER [ps OPTIONS]
    # 连接到正在运行中的容器 【慎用】 eg:docker attach b22cc1880b7a
    docker attach [OPTIONS] CONTAINER
    # 从服务器获取实时事件
    docker events [OPTIONS]
    # 获取容器的日志
    docker logs [OPTIONS] CONTAINER
    # 阻塞对指定容器的其它调用方法,直到容器停止后退出阻塞
    docker wait [OPTIONS] CONTAINER [CONTAINER...]
    # 将文件系统作为一个tar归档文件导出到STDOUT eg:docker export -o mysql.tar a404c6c174a2
    docker export [OPTIONS] CONTAINER
    # 从归档文件中创建镜像 eg:docker import my_ubuntu_v3.tar runoob/ubuntu:v4
    docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
    # 列出指定的容器的端口映射,或者查找将PRIVATE_PORT NAT到面向公众的端口 eg:docker port mymysql
    docker port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]
    # 删除一个或多个容器 eg:docker rm -f db01
    docker rm [OPTIONS] CONTAINER [CONTAINER...]
    # 创建一个新的容器但不启动它 eg:docker create --name myrunoob nginx:latest
    docker create [OPTIONS] IMAGE [COMMAND] [ARG...]

容器生命周期管理

docker run 创建一个新的容器并运行一个命令【重要】

语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG…]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
OPTIONS说明:
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-P: 随机端口映射,容器内部端口随机映射到主机的高端口
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name="nginx-lb": 为容器指定一个名称;
--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 设置环境变量;
--env-file=[]: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
--link=[]: 添加链接到另一个容器;
--expose=[]: 开放一个端口或一组端口;
--volume , -v: 绑定一个卷

eg:

1
2
3
4
# 使用docker镜像nginx:latest以后台模式启动一个容器,并将容器命名为mynginx
docker run --name mynginx -d nginx:latest
# 使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,主机的目录 /data 映射到容器的 /data
docker run -p 80:80 -v /data:/data -d nginx:latest

start/stop/restart 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
docker start :启动一个或多个已经被停止的容器
docker stop :停止一个运行中的容器
docker restart :重启容器
docker kill :杀掉一个运行中的容器
docker pause :暂停容器中所有的进程
docker unpause :恢复容器中所有的进程
# 语法:
docker start [OPTIONS] CONTAINER [CONTAINER...]
docker stop [OPTIONS] CONTAINER [CONTAINER...]
docker kill [OPTIONS] CONTAINER [CONTAINER...]
docker restart [OPTIONS] CONTAINER [CONTAINER...]
docker pause [OPTIONS] CONTAINER [CONTAINER...]
docker unpause [OPTIONS] CONTAINER [CONTAINER...]

docker exec 在运行的容器中执行命令【重要】

语法:docker exec [OPTIONS] CONTAINER COMMAND [ARG…]

1
2
3
4
OPTIONS说明:
-d :分离模式: 在后台运行
-i :即使没有附加也保持STDIN 打开
-t :分配一个伪终端

eg:
1
docker exec -it 432c029981fa /bin/sh 

Dockerfile

它是用户创建自定义镜像的文件。它通常分为四部分:基础镜像信息,维护者信息,镜像操作指令和容器启动时的指令
eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#基础系统信息,基于ubuntu 14.04构建的  
FROM ubuntu:14.04
MAINTAINER Alex McLain
RUN apt-get -qq update
#安装apache、hg、php5
RUN apt-get -y install apache2 apache2-utils curl mercurial php5 php5-cli php5-mcrypt
# Configure hgweb
ADD hg/add.php /etc/default/hgweb/hg/
#创建一个挂载点,本机或其他容器可以将其挂载。启动时用-v参数进行挂载
VOLUME /var/hg
VOLUME /etc/apache2/sites-available
#暴露的端口号,启动时要通过-p参数指定
EXPOSE 80
#启动时执行的命令
CMD load-default-scripts && service apache2 start && /bin/bash

参数说明:

  • MAINTAINER:设置该镜像的作者。语法:MAINTAINER
  • RUN:在shell或者exec的环境下执行的命令。RUN指令会在新创建的镜像上添加新的层面,接下来提交的结果用在Dockerfile的下一条指令中。语法:RUN 《command》
  • ADD:复制文件指令。destination是容器内的路径。source可以是URL或者是启动配置上下文中的一个文件。语法:ADD 《src》 《destination》
  • CMD:提供了容器默认的执行命令。 Dockerfile只允许使用一次CMD指令。 使用多个CMD会抵消之前所有的指令,只有最后一个指令生效。 CMD有三种形式:CMD [“executable”,”param1”,”param2”],CMD [“param1”,”param2”],CMD command param1 param2
  • EXPOSE:指定容器在运行时监听的端口。语法如下:EXPOSE ;
  • ENTRYPOINT:配置给容器一个可执行的命令,这意味着在每次使用镜像创建容器时一个特定的应用程序可以被设置为默认程序。同时也意味着该镜像每次被调用时仅能运行指定的应用。类似于CMD,Docker只允许一个ENTRYPOINT,多个ENTRYPOINT会抵消之前所有的指令,只执行最后的ENTRYPOINT指令。语法:ENTRYPOINT [“executable”, “param1”,”param2”],ENTRYPOINT command param1 param2
  • WORKDIR:指定RUN、CMD与ENTRYPOINT命令的工作目录。语法:WORKDIR /path/to/workdir
  • ENV:设置环境变量。它们使用键值对,增加运行程序的灵活性。语法:ENV
  • USER:镜像正在运行时设置一个UID。语法:USER
  • VOLUME:授权访问从容器内到主机上的目录。语法:VOLUME [“/data”]

docker-compose

脚本安装

1
2
curl -L https://github.com/docker/compose/releases/download/1.1.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

pip安装

1
pip install -U docker-compose 

docker-compose.yml编写

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wiki2:
image: 'nickstenning/mediawiki'
ports:
- "8880:80"
links:
- db:database
volumes:
- /data/wiki2:/data

db:
image: "mysql"
expose:
- "3306"
environment:
- MYSQL_ROOT_PASSWORD=defaultpass

文档:https://docs.docker.com/engine/reference/builder/#dockerfile-examples

执行脚本

1
docker-compose up -d

docker 镜像加速

1
2
3
4
5
6
7
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://oyukeh0j.mirror.aliyuncs.com"]
}
EOF
systemctl restart docker

参考文档

https://www.kancloud.cn/docker_practice/docker_practice/469767
https://docs.docker.com/engine/reference/builder/#dockerfile-examples
https://www.kancloud.cn/hfpp2012/docker/467104

简介

systemd作为系统启动方式,每一个服务以.service结尾,一般会分为3部分:Unit、Service和Install

Unit部分

服务的说明内容, 文档介绍以及对一些依赖服务定义

  • Description 简单描述服务
  • After 在什么服务启动之后
  • Before 在什么服务启动之前启动
  • Requires 依赖其他的单元服务, 需要与列出的服务一起激活,若任何服务无法启动,则该单元不会被激活
  • Wants 比Requires依赖性弱,弱其他服务没有启动成功,该服务也不受影响,只是表示一种推荐

Service部分

服务的一些具体运行参数的设置

  • Type
    • simple:ExecStart字段启动的进程为主进程(默认)
    • forking: ExecStart字段以fork方式启动,此时父进程将退出,子进程将成为主进程(后台运行),一般都设置为forking
    • oneshot: 类似于simple,但只执行一次,systemd会等它执行完,才启动其他服务
    • dbus:类似于simple, 但会等待D-Bus信号后启动
    • notify: 类似于simple, 启动结束后会发出通知信号,然后systemd再启动其他服务
    • idle:类似于simple,但是要等到其他任务都执行完,才会启动该服务
  • EnvironmentFile:指定配置文件,和连词号(-)组合使用,,表示抑制错误,即发生错误时,不影响其他命令的执行。eg:EnviromentFile=-/etc/sysconfig/xxx 表示即使文件不存在,也不会抛异常
  • Environment: 后面接多个不同的shell变量。eg:Environment=DATA_DIR=/data/elk
  • KillMode:
    • control-group:当前控制组里的所有子进程,都会被杀掉(默认)
    • process: 只杀主进程
    • mixed: 主进程将收到SIGTERM信号,子进程收到SIGKILL信号
    • none: 没有进程会被杀掉,只是执行服务的stop命令
  • Restart的类型:
    • no(默认值):退出后无操作
    • on-success: 只有正常退出时(退出状态码为0),才会重启
    • on-failure: 非正常退出时,重启,包括被信号终止和超时等,对于守护进程,推荐用on-failure
    • on-abnormal:只有被信号终止或超时,才会重启
    • on-abort:只有在收到没有捕捉到的信号终止时,才会重启
    • on-watchdog: 超时退出时,才会重启
    • always: 不管什么退出原因,都会重启
  • WantedBy:
    • multi-user.target: 表示多用户命令行状态,这个设置很重要,一般设置为multi-user.target
    • graphical.target: 表示图形用户状体,它依赖于multi-user.target
  • PIDFile:PID的文件路径
  • PrivateTmp:是否分配独立的临时空间
  • ExecStart:启动服务时执行的命令
  • ExecReload:重启服务时执行的命令
  • ExecStop:停止服务时执行的命令
  • ExecStartPre:启动服务前执行的命令
  • ExecStartPost:启动服务后执行的命令
  • ExecStopPost:停止服务后执行的命令
  • StartLimitInterval: 无限次重启,默认是10秒内如果重启超过5次则不再重启,设置为0表示不限次数重启
  • RestartSec:表示systemd重启服务之前,需要等待的秒数:RestartSec: 30 ,默认值0.1(s)
    注意:启动、重启、停止命令全部要求使用绝对路径,使用相对路径则会报错!

    服务保存位置

    脚本的权限为754,脚本一般存放在/usr/lib/systemd中 , 目录下又有user和system之分
  • /usr/lib/systemd/system :系统服务,开机不需要登录就能运行的程序(相当于开机自启)
  • /usr/lib/systemd/user:用户服务,需要登录后才能运行的程序

    systemctl命令用法

    systemctl start [服务名(也是文件名)]
    systemctl restart [服务名(也是文件名)]
    systemctl stop [服务名(也是文件名)]
    systemctl status [服务名(也是文件名)]
    systemctl enable [服务名(也是文件名)]
    systemctl disable [服务名(也是文件名)]

    举例

    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
    [Unit]
    Description=Docker Application Container Engine
    Documentation=http://docs.docker.com
    After=network.target
    Wants=docker-storage-setup.service
    Requires=docker-cleanup.timer

    [Service]
    Type=notify
    NotifyAccess=main
    EnvironmentFile=-/run/containers/registries.conf
    EnvironmentFile=-/etc/sysconfig/docker
    EnvironmentFile=-/etc/sysconfig/docker-storage
    EnvironmentFile=-/etc/sysconfig/docker-network
    Environment=GOTRACEBACK=crash
    Environment=DOCKER_HTTP_HOST_COMPAT=1
    Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin
    ExecStart=/usr/bin/dockerd-current \
    --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current \
    --default-runtime=docker-runc \
    --exec-opt native.cgroupdriver=systemd \
    --userland-proxy-path=/usr/libexec/docker/docker-proxy-current \
    --init-path=/usr/libexec/docker/docker-init-current \
    --seccomp-profile=/etc/docker/seccomp.json \
    $OPTIONS \
    $DOCKER_STORAGE_OPTIONS \
    $DOCKER_NETWORK_OPTIONS \
    $ADD_REGISTRY \
    $BLOCK_REGISTRY \
    $INSECURE_REGISTRY \
    $REGISTRIES
    ExecReload=/bin/kill -s HUP $MAINPID
    LimitNOFILE=1048576
    LimitNPROC=1048576
    LimitCORE=infinity
    TimeoutStartSec=0
    Restart=on-abnormal
    KillMode=process

    [Install]
    WantedBy=multi-user.target

    相关文档

    https://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html
    https://wizardforcel.gitbooks.io/vbird-linux-basic-4e/content/150.html

Bean初始化执行顺序

  • 1、构造方法
  • 2、以来注入、属性设置
  • 3、@PostConstruct注解的方法(反射机制调用)
  • 4、afterPropertiesSet方法(实现InitializingBean接口)
  • 5、init-method指定的方法(xml中,通过反射机制调用)
  • 6、bean自己玩耍
  • 7、destory-method指定的方法(xml中,通过反射机制调用)
  • 8、destroy方法(实现DisposableBean接口)
  • 9、@PreDestroy注解的方法(反射机制调用)

    @PostConstruct和 init-method方法都是通过反射调用,所以效率不高,建议使用方法3

@PostConstruct和@PreDestroy 实现原理

@PostConstruct和@PreDestroy是通过Spring的后置处理器InitDestroyAnnotationBeanPostProcessor实现功能,如图:

InitDestroyAnnotationBeanPostProcessor

添加依赖

1
2
3
4
 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Spring Boot Actuator

服务监控与管理组件

自定义endpoint

在类上增加注解@Endpoint,在方法上增加注解@ReadOperation、@WriteOperation、@DeleteOperation

1
2
3
4
5
6
7
8
9
10
11
@Component
@Endpoint(id = "dennis")
public class DennisEndpoint {
@ReadOperation
public Map<String, String> hello() {
Map<String, String> result = new HashMap<>();
result.put("author", "dennis");
result.put("age", "24");
return result;
}
}

访问url: http://localhost:8080/actuator/dennis

  • @ReadOperation GET请求,响应状态为 200 如果没有返回值响应 404(资源未找到)
  • @WriteOperation POST请求,响应状态为 200 如果没有返回值响应 204(无响应内容)
  • @DeleteOperation DELETE请求,响应状态为 200 如果没有返回值响应 204(无响应内容)

HttpTraceEndpoint -> HttpTraceRepository.findall()(接口) -> InMemoryHttpTraceRepository.add()

HttpTraceFilter -> OncePerRequestFilter -> GenericFilterBean(把spring的一家人带进来了) -> Filter

Actuator
Endpoint
HealthIndicator -> AbstractHealthIndicator

Actuator
Endpoint
HealthIndicator

http://blog.battcn.com/

参考文档

http://blog.battcn.com/2018/05/24/springboot/v2-actuator-introduce/