WeiyiGeek

杂而不纯,不博也不精 | 学不止步,勿忘初心

无标题

[TOC]


0x00 Docker 排查项

CentOS7:

# Systemctl 启动项参数
/etc/systemd/system/docker.service
/usr/lib/systemd/docker.service

# Docker 元数据目录
/var/lib/docker

# Docker Deamon启动项
/etc/sysconfig/docker


0x01 Docker 异常解决

报错问题1:
错误信息:

docker:Error running DeviceCreate (createSnapDevice) dm_task_run failed

解决办法:https://stackoverflow.com/questions/30719896/docker-dm-task-run-failed-error

#不同安装路径可能不同
service docker stop
thin_check /var/lib/docker/devicemapper/devicemapper/metadata
thin_check --clear-needs-check-flag /var/lib/docker/devicemapper/devicemapper/metadata
service docker start


报错问题2:
错误信息:

docker start e7e
Error response from daemon: devmapper: Error mounting '/dev/mapper/docker-253:4-11534337-ee772425c4996ca581e5c234806adf41aede9424a83ce1402596105a9f66434d' on '/export/docker/devicemapper/mnt/ee772425c4996ca581e5c234806adf41aede9424a83ce1402596105a9f66434d': invalid argument

错误原因:因为selinux enable的时候,创建了该容器。而后修改了/etc/selinux/config 修改成selinux为disabled。
物理机重启后selinux处于关闭状态,则原先在selinux enable时候创建的容器就会无法启动报出这种错误。
修复方法:

主要有两种:
1.可以将selinux重新置为enable然后重启物理机即可修复。
2.修改容器的配置,比如我的容器的配置是/var/lib/docker/containers/e7ef71494940ba293be4b3f74198bf34835c35537810053b051d9a6c33adbd32/config.v2.json文件。将其中的"MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c12,c257", "ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c12,c257"重修修改为"MountLabel": "", "ProcessLabel": "",然后重新启动docker daemon,容器即可修复。


报错问题3:
错误信息:

/usr/bin/docker-current: Error response from daemon: devmapper: Thin Pool has 155398 free data blocks which is less than minimum required 163840 free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior

解决办法:

sudo docker rm $(sudo docker ps -q -f status=exited)
sudo docker volume rm $(sudo docker volume ls -qf dangling=true)
sudo docker rmi $(sudo docker images --filter "dangling=true" -q --no-trunc)


报错问题4:
运行环境: CentOS 7.3.1611 , Docker Version 1.12.6-16.el7.centis.x86_64 , API 1.24;
报错信息:

#Docker 启动报错
docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/docker.service.d
└─flannel.conf
Process: 5226 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 $OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS $ADD_REGISTRY $BLOCK_REGISTRY $INSECURE_REGISTRY (code=exited, status=1/FAILURE)
Main PID: 5226 (code=exited, status=1/FAILURE)
#错误关键点
dockerd-current[5226]: time="..." level=info msg="libcontainerd: new containerd process, pid: 5238"
dockerd-current[5226]: time="..." level=warning msg="devmapper: Usage of loopback devices is strongly discouraged for production use. Please use `--storage-opt dm.thinpooldev` or use `man docker` to refer to dm.thinpooldev section."
node-198 dockerd-current[5226]: time="2020-01-18T17:00:27.872191345+08:00" level=error msg="[graphdriver] prior storage driver \"devicemapper\" failed: devmapper: Base Device UUID and Filesystem verification failed: devmapper: Current Base Device UUID:59df6192-df22-4d88-9e90-02755e7e3242 does not match with stored UUID:24907e3f-5114-4948-91ea-c1a4e92854ef. Possibly using a different thin pool than last invocation"
node-198 dockerd-current[5226]: time="2020-01-18T17:00:27.872410561+08:00" level=fatal msg="Error starting daemon: error initializing graphdriver: devmapper: Base Device UUID and Filesystem verification failed: devmapper: Current Base Device UUID:59df6192-df22-4d88-9e90-02755e7e3242 does not match with stored UUID:24907e3f-5114-4948-91ea-c1a4e92854ef. Possibly using a different thin pool than last invocation"

错误原因:由于存放Docker的Metadata磁盘是挂载上来的,在某次关机的时候存储异常关闭在解决后机器挂载上远程的NFS磁盘,在挂载后磁盘的UUID发生变化,导致通过loopback的方式不能连接到Docker的DeviceMapper的存储池;
解决方法:查看实际的loop0的uuid并且修改deviceset-metadata中的UUID

#查看系统磁盘UUID
$ls /dev/disk/by-uuid
$blkid
#59df6192-df22-4d88-9e90-02755e7e3242

#常规路径
/var/lib/docker/devicemapper/metadata/deviceset-metadata
#自定义的路径
/disk/docker/devicemapper/metadata/deviceset-metadata
#内容设置
{"next_device_id":1,"BaseDeviceUUID":"59df6192-df22-4d88-9e90-02755e7e3242","BaseDeviceFilesystem":"xfs"}

注意事项:

  • 目前docker支持的存储驱动类型有aufs/Device mapper/btrfs/overlayfs和zfs并且都采用写时复制(CoW)的技术,但是在CentOS上默认不支持aufs;
  • 注意:Docker使用的Devicemapper存储驱动的默认模式是loopback的方式,但是它的性能和稳定性都不太好;
  • 注意:默认它是loop-lvm模式采用空闲文件来构建存储池,建议在生产环境中使用direct-lvm模式;


报错信息5:

#docker info 或者在启动时候可以看见
WARNING: Usage of loopback devices is strongly discouraged for production use

报错原因:用loopback的方式运行docker是强烈不建议的;
解决方法:

#方式1:在Docker启动项里添加DOCKER_STORAGE_OPTIONS(不推荐,仅仅是忽略警告)
DOCKER_STORAGE_OPTIONS="--storage-opt dm.no_warn_on_loop_devices=true"

#方式2:在docker daemon启动时,加入device mapper的元数据存储和docker的镜像数据存储选择独立的块设备即可,lvm或者独立磁盘分区都可以
--storage-opt dm.datadev=/dev/xxxx --storage-opt dm.metadatadev=/dev/xxx

WeiyiGeek.解决方法

阅读更多
无标题

[TOC]

0x00 前言基础

什么是JDBC驱动?
答:数据库连接JAVA Database Connectivity java

为什么会出现JDBC?
SUN公司提供的一种数据库访问规则、规范, 由于数据库种类较多,并且java语言使用比较广泛,sun公司就提供了一种规范,让其他的数据库提供商去实现底层的访问规则。 我们的java程序只要使用sun公司提供的jdbc驱动即可。


驱动下载和使用

描述:在利用JAVA的JDBC连接到MySQL或者其它数据库的时候,需要加载其jar包到工程的lib库中;

方式1:JDBC驱动包

MySQL8.x的JDBC驱动包下载页面: https://dev.mysql.com/downloads/connector/j/8.0.html

WeiyiGeek.官网下载JDBC

MySQL JDBC API:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html

JAVA连接数据库的JDBC驱动关于MySQL5.x和MySQL8.X版本:
描述:MySQL 8.0 开始数据库相比常用的 5.X 版本发生了比较大的变化,我们在采用JDBC连接数据库的过程中也相应的发生变化比如驱动包版本,驱动名称等等;
直接下载地址:https://dev.mysql.com/downloads/file/?id=477058

  • 1.MySQL 版本和 mysql-connector-java 版本对应关系如下:
    | Connector/J version | Driver Type | JDBC version | MySQL Server version | Status |
    | ——————- | ———– | —————— | ——————– | —————————————– |
    | 5.1 | 4 | 3.0, 4.0, 4.1, 4.2 | 5.6, 5.7, 8.0* | General availability |
    | 8.0 | 4 | 4.2 | 5.6, 5.7, 8.0 | General availability. Recommended version |

  • 2.将 com.mysql.jdbc.Driver 更换为 com.mysql.cj.jdbc.Driver;

  • 3.MySQL 8.0 以上版本不需要建立 SSL 连接的,需要显式关闭useSSL=false,由于 MySQL 5.7 之前版本安全性做的并不够好,比如安装时生成的root空密码账号、存在任何用户都能连接上的 test 库等,导致数据库存在较大的安全隐患,所以MySQL从5.7版本开始加强安全性问题的修复到了 MySQL 8.0 以上版本已经不需要使用 SSL 进行连接加密了,但是任然保留这个接口;

  • 4.设置 CST 时区: serverTimezone=UTC,否则会启动报错

    Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

MySQL8.X的JDBC驱动连接案例:

Class.forName("com.mysql.cj.jdbc.Driver");
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test_demo?useSSL=false&serverTimezone=UTC","root","password");


方式2:maven依赖下载

采用maven搜索网站:https://mvnrepository.com/ ,搜寻可用的配置;

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>


工程加载Lib

新建立一个Eclipse工程并且创建一个lib目录,将下载的jar包复制到其中;右键点击jar包选择 Build Path -> Add to Bulid Path;

WeiyiGeek.Build Path


0x01 基础使用

描述:JDBC基本步骤流程:

  • 1.注册驱动
  • 2.建立链接
  • 3.创建statement
  • 4.构建并执行SQL
  • 5.获取结果集ResultSet
  • 6.遍历结果集
  • 7.释放资源


基础实例:

package com.weiyi.Jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.mysql.cj.jdbc.result.ResultSetMetaData;

public class Demo1 {
4@SuppressWarnings("unused")
4public static void main(String[] args) throws SQLException {
44
44//JDB连接标准文档
44Connection conn = null;
44Statement st = null;
44ResultSet rs = null;
44try {
444//Step 1.驱动注册(实际上不建议采用此类方法加载驱动-他会注册两次)
444DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
444
444//Step 2.构建连接字符串和建立链接
444String urlFormat = "jdbc:mysql://%s:%d/%s?useUnicode=true&characterEncoding=UTF-8";
444String connectionUrl = String.format(urlFormat, "113.xx.xx.xxx", 3306, "Demo");
444conn = DriverManager.getConnection(connectionUrl, "root", "WeiyiGeek");
444
444//Step 3.创建statement
444st = conn.createStatement();
444
44
444//Step 4.构建SQL语句以及执行语句
444String sql = "SELECT ID AS '序号',LastName AS '名称' FROM Persons WHERE ID <> 102";
444rs = st.executeQuery(sql);
444
444//Step 5.遍历数据库
444while(rs.next()){
4444//System.out.println("ID: " + rs.getInt("ID") + " , LastName = " + rs.getString("LastName")); //注意此处使用别名的时候(不能采用字段名进行获取数据库返回的值);
4444System.out.println("ID: " + rs.getInt("序号") + " , LastName = " + rs.getString("名称"));
444}
444
444//Step 6.获取元数据metadate
444ResultSetMetaData rsmd = (ResultSetMetaData) rs.getMetaData();
444int numCols = rsmd.getColumnCount(); //获取列元素数据量
444int count = 1;
444while(count <= numCols) {
4444System.out.printf("第 %d 列: 列名: %s , AS别名: %s , 类型:%s \n",count, rsmd.getColumnName(count), rsmd.getColumnLabel(count), rsmd.getColumnType(count));
4444count++;
444}
44
44} catch (SQLException sqlEx) {
444// TODO: handle exception
444sqlEx.printStackTrace();
44} finally {
444//Step 7.释放资源(非常重要) - 从后往前
444System.out.println("Start-释放资源中");
444//结果集对象
444try {
4444if(rs != null)
44444rs.close();
444} catch (SQLException e) {
4444e.printStackTrace();
444} finally {
4444rs = null;
444}
444
444//statement对象
444try {
4444if(st != null)
44444st.close();
444} catch (SQLException e) {
4444e.printStackTrace();
444} finally {
4444st = null;
444}
444
444//数据库连接对象
444try {
4444if(conn != null)
44444conn.close();
444} catch (SQLException e) {
4444e.printStackTrace();
444} finally {
4444conn = null;
444}
444System.out.println("Successful-资源释放完成!");

444//当然您也可以采用自己封装后的JDBC工具类(非常注意释放的顺序)
444//JDBCUtil.release(conn,st,rs);
44}
4}
}

执行结果:

ID: 100 , LastName = WeiyiGeek
ID: 101 , LastName = Admin
ID: 103 , LastName = Weiyi
ID: 104 , LastName = Young
ID: 105 , LastName = bb204949-3283-11ea-b468-0242ac120002
第 1 列: 列名: ID , AS别名: 序号 , 类型:4
第 2 列: 列名: LastName , AS别名: 名称 , 类型:12
Start-释放资源中
Successful-资源释放完成!


自定义工具包类

补充:JDBC连接MySQL工具包类

  • 1.释放资源的工具类
  • 2.驱动防二次注册,因为Driver类里面有静态代码块,一上来就执行了所以等同于我们注册了两次驱动;
  • 3.构JDBC工具类的构造方法设置连接信息
//该包下的类可以通过静态类 类.方法()进行调用
//该包下的类可以通过静态类 类.方法()进行调用
package com.weiyi.Jdbc;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtil {
4static String connUrl = "jdbc:mysql://%s:%d/%s?useUnicode=true&characterEncoding=UTF-8";
4static String connIp = "13.62.17.23";
4static int connPort = 9301;
4static String conndatabase = "Demo";
4static String driverClass = null; //使用的时候添加
4static String url = null;
4static String user = null;
4static String pass = null;
4
4//静态代码块,加载类的时候执行
4static {
44try {
444//Step1.创建一个属性配置对象
444Properties prop = new Properties();
44
444//Step2.打开配置文件
444//InputStream ins = new FileInputStream("jdbc.properties");
444InputStream ins = Demo3.class.getClassLoader().getResourceAsStream("jdbc.properties");

444//Step3.导入输入流
444prop.load(ins);
44
444//Step4.属性读取
444driverClass = prop.getProperty("jdbc.driverClassName");
444url = String.format(prop.getProperty("jdbc.url"),connIp,connPort,conndatabase);
444user = prop.getProperty("jdbc.username");
444pass = prop.getProperty("jdbc.password");
44} catch (Exception e) {
444// TODO Auto-generated catch block
444e.printStackTrace();
44} finally {
444System.out.println("Properties配置已经加载!");
44}
4}
4
4public JDBCUtil() {
44super();
44// TODO Auto-generated constructor stub
4}
4public JDBCUtil(String ip,int port,String database) {
44connIp = ip;
44connPort = port;
44conndatabase = database;
4}

4//注册工具方法
4/**
* 驱动注册和建立链接
* @param user
* @param password
* @return Connection
* @throws SQLException
*/
4public static Connection getConn() throws SQLException {
44Connection conn = null;
44System.out.println("连接字符串:" + url);
44try {
444//防止驱动二次注册自动注册驱动与建立连接
444conn = DriverManager.getConnection(url, user, pass);
44} catch (SQLException e) {
444e.printStackTrace();
44}
44return conn;
4}
4
4
4/**
* 释放工具类
* @param conn
* @param st
* @param rs
*/
4
4// 注意点:导包需要查看是哪一个包的返回值
4public static void release(Connection conn, Statement st, ResultSet rs) {
44//注意点:关闭的顺序
44closeRs(rs);
44closeSt(st);
44closeConn(conn);
44System.out.println("END-资源释放完成!");
4}

4//私有静态方法-释放查询结果集
4private static void closeRs(ResultSet rs) {
44try {
444if(rs != null)
4444rs.close();
44} catch (SQLException e) {
444e.printStackTrace();
44} finally {
444rs = null;
44}
4}
4
4//私有静态方法-释放statement对象
4private static void closeSt(Statement st) {
44try {
444if(st != null)
4444st.close();
44} catch (SQLException e) {
444e.printStackTrace();
44} finally {
444st = null;
44}
4}
4
4//私有静态方法-
4private static void closeConn(Connection conn) {
44try {
444if(conn != null)
4444conn.close();
44} catch (SQLException e) {
444e.printStackTrace();
44} finally {
444conn = null;
44}
4}
}

注意事项:

  • 注:在实际使用中我们可以不用Class.forName()加载驱动了,在DriverManager.getConenect()方法中,在JDBC4.0版本后会在导入的数据库驱动包的Meta-INF中services里的java.sql.Driver驱动名称;
  • 注:在需要连接多个数据库的时候,为了区分最好是写上驱动名称当然不写也是可以的;

WeiyiGeek.Class.forName


配置文件导入

描述:我们采用properties配置文件进行导入jdbc的驱动名称以及连接字符串和账号密码等等;

比如:在工程src目录下声明一个config.properties文件(如果是使用框架的时候一般会存放在WEB-INF里面):

driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student??useUnicode=true&characterEncoding=UTF-8
name=root
password=root

补充说明:

//使用类加载器去读取src底下的资源文件后面在servlet  
//对应文件位于src目录底下在编译打包后存在在bin目录同层中,使用getClassLoader()在加载字节码文件时候顺便也加载了我们制定的资源文件
//InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");

MySQL数据库的CRUD表述:

  • 1.Create
  • 2.Retrieve 读取
  • 3.Update
  • 4.Delete

MySQL的JDBC库执行SQL方法分类:

  • executeQuery(String sql)
  • executeUpdate(String sql) : 主要针对于DML的语句如insert,update,delete语句,并且返回影响的行数;

基础实例:

package com.weiyi.Jdbc;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import com.mysql.cj.jdbc.result.ResultSetMetaData;

import javafx.scene.control.SplitPane.Divider;

public class Demo3 {
4/**
* JDBC 连接参数采用 Properties配置文件进行导入
* @param args
*/
4 //使用静态代码块读取属性(当类加载的时候执行)
4static String driverClass = null;
4static String url = null;
4static String user = null;
4static String pass = null;
4
4static {
44try {
444//Step1.创建一个属性配置对象
444Properties prop = new Properties();
44
444//Step2.打开配置文件
444//InputStream ins = new FileInputStream("jdbc.properties"); //在根目录中可以采用这种方式
444InputStream ins = Demo3.class.getClassLoader().getResourceAsStream("jdbc.properties");

444//Step3.导入输入流
444prop.load(ins);
44
444//Step4.属性读取
444driverClass = prop.getProperty("jdbc.driverClassName");
444url = prop.getProperty("jdbc.url");
444user = prop.getProperty("jdbc.username");
444pass = prop.getProperty("jdbc.password");
44} catch (Exception e) {
444// TODO Auto-generated catch block
444e.printStackTrace();
44} finally {
444System.out.println("- #ProPerties配置文件读取完成!");
44}
44
4}
4
4public static void main(String[] args) {
44//JDB连接标准文档
44Connection conn = null;
44Statement st = null;
44ResultSet rs = null;
44
44try {
444//1.驱动注册
444Class.forName(driverClass); //实际上这句话都可以免了在JDBC4.0之后他会自动在jdbc的数据库驱动jar包中元数据进行查看
444//2.建立连接
444conn = DriverManager.getConnection(url, user, pass);
444//3.建立statement对象
444st = conn.createStatement();
444//4.构建SQL语句并且执行
444rs = st.executeQuery("SELECT * FROM Persons WHERE (ID = 100)"); //Retrieve
444//5.获取数据
444ResultSetMetaData rsmd = (ResultSetMetaData) rs.getMetaData(); //获取源数据
444int len = rsmd.getColumnCount(); //字段梳理
444int count = 1;
444while(count <= len) {
4444System.out.print(rsmd.getColumnName(count) + " | ");
4444count++;
444}
444System.out.println("");
444while (rs.next()) {
4444System.out.println(rs.getInt("ID") + "| " + rs.getString("LastName"));
444}
444
444//6.数据库的CRUD;
444String sql = "INSERT INTO Persons VALUE (NULL,'Weiyi')"; //主要Primary Key 插入主键的时候可以用null代替
444int result = st.executeUpdate(sql); //该方法主要执行 INSERT, UPDATE or DELETE 等语句,返回影响的行数
444//如果返回值大于0则表明操作成功,否则失败;
444if(result > 0) {
4444System.out.println("插入成功 : "+ sql);
444}else {
4444System.out.println("插入失败");
444}
444
444// U :
444String sqlUpdate = "UPDATE Persons SET LastName = 'Whoami' WHERE ID = 100";
444result = st.executeUpdate(sqlUpdate);
444if(result > 0) {
4444System.out.println("更新成功 : " + sqlUpdate);
444}else {
4444System.out.println("更新失败");
444}
4444
444// D:
444String sqlDelete = "DELETE FROM Persons WHERE LastName = 'Weiyi'";
444result = st.executeUpdate(sqlDelete);
444if( result > 0) {
4444System.out.println("删除成功 : " + sqlDelete);
444}else {
4444System.out.println("删除失败");
444}
44444
44} catch (SQLException e) {
444// TODO: handle exception
44} finally {
444//End.释放资源
444JDBCUtil.release(conn, st, rs);
44}
4}
}

执行结果:

- #ProPerties配置文件读取完成!
查询成功 : SELECT * FROM Persons WHERE (ID = 100)
ID | LastName |
100| Whoami
插入成功 : INSERT INTO Persons VALUE (NULL,'Weiyi')
更新成功 : UPDATE Persons SET LastName = 'Whoami' WHERE ID = 100
删除成功 : DELETE FROM Persons WHERE LastName = 'Weiyi'
读取完成
END-资源释放完成!


junit 单元测试

描述:在写代码的时候我们常常需要对所写的代码进行测试,如果直接在别人开发code的包下测试是比较混乱,建议将里面的方法进行抽取到测试包里,然后采用junit框架进行测试;

操作步骤:

  • 1.创建一个测试包依赖包org.junit.Test,定义一个类Testxxx然后在里面定义需要测试的方法,它还可建立多个方法进行测试;
  • 2.添加junit框架的支持及引入jar包:工程右键 - build path - add Library - Junit - Junit4;
  • 3.在需要测试的方法上面加入注解标记 @Test
  • 4.光标选择所需要测试的方法名称然后右键执行单元测试或者是打开outline视图,然后选择方法右键采用junit执行;

WeiyiGeek.junit

基础实例:

package com.weiyi.Test;

import java.util.Date;
import org.junit.Test;

/**
* 使用junit进行单元测试
* @author WeiyiGeek
*/
public class MainTest {
4
4//单元测试需要测试的方法
4@Test
4public void testPrint() {
44Date date = new Date();
44System.out.println("当前时间:" + date.toGMTString());
4}
}

WeiyiGeek.jUnit单元测试


Dao 开发模式

描述:Data Access Object 数据访问对象.即使用包类对象实现一个功能;

模式建立流程;

  • 1.建立一个dao的接口,里面声明数据库访问规则;
  • 2.新建一个dao的实现类,具体实现早前定义的规则;
  • 3.建立一个调用dao接口中的方法进行展示实现类的运行结果;
-- (1) 建立一个测试的表
CREATE TABLE user_log (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '序号',
userLogin VARCHAR(255) NOT NULL COMMENT '登陆名称',
4userPass VARCHAR(255) NOT NULL COMMENT '登陆密码',
loginTime DATETIME NOT NULL DEFAULT NOW() COMMENT '登陆时间'
);

-- (2) 数据插入
INSERT INTO user_log(id,userLogin) VALUES (NULL,'WeiyiGeek');

WeiyiGeek.

基础示例:

// 1.接口
package com.weiyi.dao;
public interface userDao {
4/**
* Dao模型-接口定义操作数据库的方法
*/
4void findAll();
}


// 2.实现接口
package com.weiyi.dao.impl;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.weiyi.Jdbc.JDBCUtil;
import com.weiyi.dao.userDao;
public class userDaoImpl implements userDao{
4//JDBC连接标准文档
4Connection conn = null;
4Statement st = null;
4ResultSet rs = null;
4
4@Override
4public void findAll() {
44try {
444//1.驱动加载和建立链接
444conn = JDBCUtil.getConn();
444//2.建立流对象statement
444st = conn.createStatement();
444//3.构建执行SQL语句 (这里的SQL语句是拼接的容易导致安全问题)
444rs = st.executeQuery("SELECT * FROM user_log");
444while(rs.next()){
4444System.out.println(rs.getInt("id") + " " + rs.getString("userLogin") + " " + rs.getDate("loginTime"));
444}
44} catch (Exception e) {
444// TODO Auto-generated catch block
444e.printStackTrace();
44} finally {
444JDBCUtil.release(conn, st, rs);
44}
4}
}


// 3.调用接口
package com.weiyi.Jdbc;
import com.weiyi.dao.userDao;
import com.weiyi.dao.impl.userDaoImpl;
/**
* 调用 dao 模型 实现的接口方法
* @author WeiyiGeek
*/
public class Demo4 {
4//注意:这里测试也可以采用Junit单元测试
4public static void main(String[] args) {
44//Step1.父类指向子类实现的接口
44userDao dao = new userDaoImpl();
44//Step2.直接调用其方法不用管具体的实现
44dao.findAll();
4}
}

运行结果:

Properties配置已经加载!
连接字符串:jdbc:mysql://11.62.17.20:3001/Demo?useUnicode=true&characterEncoding=UTF-8
1 WeiyiGeek 2020-01-14
END-资源释放完成!


0x02 JDBC安全开发

描述:做过渗透测试的人员和经验丰富的开发人员一定是知道对于数据库读取、插入数据的业务常常容易被SQL Inject,所以为了解决这一个安全问题常常采用占位绑定进行防止SQL注入,类似于PHP的PDO扩展类库中的PDO预处理语句;

注意:Statement 对象的安全问题;

  • 1.Statement对象执行SQL语句其实是将SQL语句先拼接再执行;
  • 2.比如下面的实例进行拼接了SQL语句,先拼接SQL语句然后再一起执行;但是如果变量中带有数据库的关键字,那么在进行查询的时候将会被认为是数据库查询的关键字,从而引发安全问题;
    -- 在Statement对象中存在的安全问题
    String sql = "SELECT * FROM user_log WHERE userLogin = '" + user + "' AND userPass = md5('" + pass + "')";

    -- 但是如果请求传入的参数是下面这样的边会出现问题
    http:\/\/127.0.0.1/login.jsp?user=Admin&pass=123456') or '1=1' or md5('123456

    -- 安全问题:最原始的万能登陆密码(现在基本不存在这样的漏洞)
    SELECT * FROM user_log WHERE userLogin='WeiyiGeek' AND userPass = MD5('123456') OR '1=1'

WeiyiGeek.Statement安全


解决办法 :

  • (1) PrepareStatement 该对象就是替换前面的statement对象, 相比较以前的statement, 预先处理给定的sql语句对其执行语法检查。
  • (2) 在sql语句里面使用 ? 占位符来替代后续要传递进来的变量; 后面进来的变量值,将会被看成是字符串,不会产生任何的关键字。
String sql = "insert into t_user values(null , ? , ?)";
ps = conn.prepareStatement(sql);
//给占位符赋值 从左到右数过来,1 代表第一个问号, 永远你是1开始。
ps.setString(1, userName);


基础实例:

// dao 模型接口
package com.weiyi.dao;
public interface userDao {
4/** Dao模型-接口定义操作数据库的方法*/
4void psLogin(String user,String pass,int x);
4void psInsert(String user,String pass);
4void psUpdate(String user,int id);
4void psDelete(String user,String pass);
}


// dao 模型接口具体实现
package com.weiyi.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.weiyi.Jdbc.JDBCUtil;
import com.weiyi.dao.userDao;

public class userDaoImpl implements userDao{
4//JDBC连接标准文档
4Connection conn = null;
4Statement st = null;
4ResultSet rs = null;
4

4/*** 创建PreparedStatement预处理对象 */
4@Override
4public void psLogin(String user,String pass, int x) {
44try {
444//1.载入数据库驱动建立链接
444conn = JDBCUtil.getConn();
444//2.构建SQL语句以及预处理SQL语句
444String sql = "SELECT * FROM user_log WHERE userLogin = ? AND userPass = md5(?) AND id = ?"; //? 占位符合后面会将绑定的参数进行格式化后传入
444PreparedStatement ps = conn.prepareStatement(sql); //关键点1:对我们的SQL语句进行预处理如果SQL语法错误的将不能通过解析
444ps.setString(1, user); //关键点2:进行传入参数的位置开始绑定从,1代表第一个问号,2同理;
444ps.setString(2, pass); //关键点3:注意传入的类型是可以根据需要来设置的;
444ps.setInt(3, x);
444//3.执行预处理好的的对象
444rs = ps.executeQuery();
444if(rs.next()) {
4444System.out.println("登陆成功!");
4444System.out.println("欢迎您" + rs.getString("userLogin") + "管理员, 注册时间: " + rs.getTimestamp("loginTime"));
444} else {
4444System.out.println("登陆失败");
444}
44} catch (Exception e) {
444// TODO: handle exception
444e.printStackTrace();
44} finally {
444JDBCUtil.release(conn, st, rs);
44}
4}
4
4
4@Override
4public void psInsert(String user, String pass) {
44PreparedStatement ps = null;
44try {
444conn = JDBCUtil.getConn();
444String sql = "INSERT INTO user_log(userLogin,userPass) VALUES (?,md5(?))";
444ps = conn.prepareStatement(sql);
444ps.setString(1, user);
444ps.setString(2, pass);
444int result = ps.executeUpdate();
444if(result > 0) {
4444System.out.println("成功添加" + user + "用户!");
444}else {
4444System.out.println("用户注册失败!");
444}
44} catch (SQLException e) {
444// TODO Auto-generated catch block
444e.printStackTrace();
44} finally {
444JDBCUtil.release(conn, ps);
44}
4}

4@Override
4public void psUpdate(String user, int id) {
44PreparedStatement ps = null;
44try {
444conn = JDBCUtil.getConn();
444String sql = "UPDATE user_log SET userLogin = ? WHERE id = ?";
444ps = conn.prepareStatement(sql);
444ps.setString(1, user);
444ps.setInt(2, id);
444int result = ps.executeUpdate();
444if(result>0) {
4444System.out.println("更新用户ID = " + id + ", 为 " + user+"用户成功!");
444}else {
4444System.out.println("更新失败");
444}
44} catch (SQLException e) {
444// TODO: handle exception
444e.printStackTrace();
44} finally {
444JDBCUtil.release(conn, ps);
44}
4}

4@Override
4public void psDelete(String user, String pass) {
44PreparedStatement ps = null;
44try {
444conn = JDBCUtil.getConn();
444String sql = "DELETE FROM user_log WHERE userLogin = ? AND userPass = md5(?)";
444ps = conn.prepareStatement(sql);
444ps.setString(1, user);
444ps.setString(2, pass);
444int result = ps.executeUpdate();
444if(result > 0){
4444System.out.println("用户 " + user +" 删除成功!");
444}else {
4444System.out.println("删除失败");
444}
444
44} catch (SQLException e) {
444// TODO Auto-generated catch block
444e.printStackTrace();
44} finally {
444JDBCUtil.release(conn, ps);
44}
4}
}

执行结果:

Properties配置已经加载!
连接字符串:jdbc:mysql://127.0.0.1:3301/Demo?useUnicode=true&characterEncoding=UTF-8
登陆成功!
欢迎您WeiyiGeek管理员, 注册时间: 2020-01-14 12:42:20.0
更新用户ID = 2, 为 Admin用户成功!
用户 Admin 删除成功!
END-资源释放完成!

JavaEE 架构

  • 客户层 (Web 浏览器 、Applet)
  • Web (Severlet、 Jsp)
  • 业务逻辑 (EJB)
  • 数据持久层 (数据库 MySQL , Oracle)
阅读更多
无标题

0x00 基础知识

Windows 操作系统发行版说明:

  • VL版本(VOL,Volume Licensing for Organizations)中文意思是团体批量许可证企业或者政府需要大量购买一个软件时可以获得优惠,其所用密钥称为VLK(Volume Licensing Key ),并且VOL可以安装于多台机器,而且不用激活在使用体验上和零售版基本没有区别。
    • 版本根据购买数量等又细分为 "开放式许可证" (Open License)、"选择式许可证 (Select License)"、"企业协议 (Enterprise Agreement)"、"学术教育许可证 (Academic Volume Licensing)"等 5 种版本;


Windows Server 2019 Standard 和 Datacenter 版本的区别

  • 1.锁定和限制
锁定和限制 Windows Server 2019 Standard Windows Server 2019 Datacenter 区别
最大用户数 基于 CAL 基于 CAL
最大 SMB 连接数 16,777,216 16,777,216
最大 RRAS 连接数 无限制 无限制
最大 IAS 连接数 2,147,483,647 2,147,483,647
最大 RDS 连接数 65,535 65,535
最大 64 位套接字数 64 64
最大核心数 无限制 无限制
最大 RAM 24 TB 24 TB
可用作虚拟化来宾 是;每个许可证允许运行 2 台虚拟机以及一台 Hyper-V 主机 是;每个许可证允许运行无限台虚拟机以及一台 Hyper-V 主机 YES
服务器可以加入域
边缘网络保护/防火墙
DirectAccess
DLNA 解码器和 Web 媒体流 是,如果安装为具有桌面体验的服务器 是,如果安装为具有桌面体验的服务器
  • 2.服务器角色
    • 常规的一些应用服务器角色都有比如:Active Directory 域服务,AD 轻型目录服务,DHCP/IIS/DNS/文件和存储服务等
    • Hyper-V支持的区别是 ,而Datacenter版本包括受防护的虚拟机
    • WDS 传输服务器是 Windows Server 2019(还有从 Windows Server 版本 1803 开始的半年频道)中服务器核心安装的新功能-
  • 3.功能
    • Windows Server 功能可以使用服务器管理器(或 PowerShell)安装容器,前者是(Windows 容器不受限制;Hyper-V 容器最多为 2 个),后者是(Windows 容器和 Hyper-V 容器不受限制);
    • 主机保护者 Hyper-V 支持:前者 否 , 后者是
    • 通常可用的功能存储副本 :前者是(1 种合作关系和 1 个具有单个 2TB 卷的资源组), 后者是无限制
    • 软件定义的网络 :前者 否 , 后者是
    • 存储空间直通 :前者 否 , 后者是
    • 继承激活 : 前者托管于数据中心时作为来宾 , 后者可以是主机,也可以是来宾

参考链接:


0x01 入门安装

描述:采用虚拟机的形式进行安装测试 Windows Server 2019 安装使用流程,下面记录主要的安装步骤;

1.点击现在安装需要进行输入产品密匙:序列号:WMDGN-G9PQG-XVVXX-R3X43-63DFG

WeiyiGeek.Step1

2.选择安装操作系统的版本(一般建议安装桌面版本)

WeiyiGeek.Step2

3.选择自定义:仅仅安装 Windows(高级) 进行安装,点击后进行驱动器格式选择,然后直接下一步即可;

WeiyiGeek.Step3

4.等待安装结束

WeiyiGeek.Step4

阅读更多
无标题

问题1.警告超委托内存设置为0,后台保存可能在低内存条件下失败
报错信息:

WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.

解决办法:

#方式1:root权限、临时生效不用重启Redis服务
echo 1 > /proc/sys/vm/overcommit_memory

#方式2:永久生效但是需要重启redis服务
vim /etc/sysctl.conf
vm.overcommit_memory=1

建议配置Redisv错误日志文件:logfile /var/log/redis/redis-server.log

阅读更多
首页 归档 分类 标签 关于 搜索