java 反射

  反射看了这么多,可以简单认为是用于动态变化类的内容,避免写死,通过配置文件,来进行修改,可以这么说,如果使用new那么如果更新需要重写代码,但是如果用反射,则可以用配置文件就可以更新,无须修改代码与重新运行编译。

Read More

事务

  事务是数据库管理系统执行过程中的一个逻辑单位,由有限个数据库操作序列组成。
  事务四个特性:

1.原子性(Atomicity):事务作为一个整体被执行,包含其中的全部数据操作,要么全部执行,要么全部不执行,即回滚到执行前状态。
2.一致性(Consistency):事务应确保数据库状态从一个一致状态转变为另一个一致状态。一致状态是数据库中的数据应与数据库的定义一致,换句话说就是满足完整性约束。
3.隔离性(Isolation):多个事务并发执行时,一个事务的执行不影响其他事务执行,换句话说,每个事务只有自己执行的效果,没含带其他事务,具有独立性,最后,不同事务先后提交并执行后,最终呈现出来的效果是串行的。
3.持久性(Durability):已被提交的事务对数据库的修改应该是永久改变的。

  隔离性最简单的实现方式就是各个事务都串行执行了,如果前面的事务还没有执行完毕,后面的事务就都等待。但是这样的实现方式很明显并发效率不高,并不适合在实际环境中使用。为了解决上述问题,实现不同程度的并发控制,SQL的标准制定者提出了不同的隔离级别:未提交读、提交读、可重复读、序列化读。

1. 未提交读(READ UNCOMMITTED)
    最低级的的隔离级别,可以读取未提交事务的数据。
2. 提交读(READ COMMITTED)
    一个事务只能看见已经提交的事务所做的改变,大多数数据库系统的默认隔离级别(但不是MYSQL默认的)。
3. 可重复读(REPEATABLE READ)
    事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容,可以说上了一个修改锁。
4. 可串行化(SERIALIZABLE)
    最高级别隔离,强制事务串行执行,时间消耗大,导致超市现象和锁竞争,一般不用该级别,而是采用乐观锁与悲观锁。

  较低的隔离级别能够提高效率,但是却会导致很多问题,常见的4个问题如下:

1.脏读
    脏读发生于未提交读级别,事务A读取事务B的修改的数据,但是事务B提交前回滚,即撤回操作,此时事务A读取的数据为无用数据,出现了脏读,脏读就是读取脏的数据(垃圾数据)。
2. 不可重复读问题(对于列说)
    不可重复读问题是说事务两次读取的数据不一致,发生于并发事务中,事务A第一次读取数据,随后,事务B修改数据的某一列,此时提交后,数据修改,此时事务A又再次读取数据,此时读取数据的某一列不一致,从而产生不可重复读问题。
3. 幻读问题(对于行说)
    幻读问题是说事务第一次读的数据与第二次读的数据数量不一致,从而产生幻觉的问题,事务A第一次读取数据,此时事务B增加或删减了一行数据后,此时事务A再次读取数据时产生了两者不一致的幻觉。
4. 丢失更新问题
    丢失更新问题是说事务A的更新被事务B的修改覆盖,从而丢失了更新,丢失问题分为两种,第一种为回滚丢失更新,在事务A执行更新时,事务B执行更新并提交,但是事务A最后回滚撤销,进而回滚到事务开始状态,此时事务B的更新也会被覆盖,第二种为提交覆盖数据更新,事务A的提交修改了期间事务B的更新的数据,从而导致了事务B更新消失,因为丢失更新1比较严重,所以数据库本身不允许这一类丢失更新的发生。

  对于不同隔离等级会出现的问题汇总如下:

隔离级别 脏读 不可重复读 幻读 丢失更新1 丢失更新2
未提交读 发生 发生 发生 不发生 发生
提交读 不发生 发生 发生 不发生 发生
可重复读 不发生 不发生 发生 不发生 不发生
可串行化 不发生 不发生 不发生 不发生 不发生

  前面说了乐观锁与悲观锁,但是这里要强调乐观锁与悲观锁是思想,不是具体实现,那些具体锁可以根据思想划分为乐观锁或悲观锁。乐观锁又叫乐观并发控制(OCC),悲观锁又叫悲观并发控制(PCC)。
  乐观锁是认为外界对数据的操作一般是不会发生冲突的,因此在操作过程不会进行加锁,而是当提交的时候才会进行检测加锁,数据库的乐观锁,并不是利用数据库本身的锁去实现的,可能是利用某种实现逻辑去实现做到乐观锁的思想。
  悲观锁是认为外界对数据的操作默认是会发生冲突的,所以在数据操作的整个过程都会处于加锁状态,保证同一时间只有一个线程可以访问到数据,通常利用数据库本身提供的锁机制去实现。
  乐观锁使用逻辑进行上锁,一般基于CAS思想进行设计,CAS思想是通过对比旧期望值a(在操作前进行读取,并进行赋值)与需要进行最终修改时读取值b进行比较,如果一致,则表明在此期间没有人进行修改,可以进行操作,而如果不一致,说明在此期间已经有人进行了修改,不执行更新,基于此思想数据库有两种方式:

Read More

代码块

  我在写markdown时,发现代码块有三种表示方法:

1.用于段落中有几句代码,不需要建立块,直接用``进行标识。
2.常用标识:使用三个```开头,最后使用```结束,可以指定哪种语言。
3.在代码之前另起一行,输入四个空格作为代码段标识。

Read More

删除表

  删除表有三种方式:

1.删除表
    DROP TABLE 表名;
2.删除表数据,而不是删除表结构,不能使用where指定具体内容。
    TRUNCATE TABLE 表名;
3.删除表数据,可与where搭配使用,删除指定内容。
    DELETE FROM 表名 WHERE 或者DELETE FROM 表名。

不同点:
    1.DROP 与 TRUNCATE 为数据库定义语言DDL,执行后自动提交,DELETE为数据库操作语言。
    2.truncate和delete 只删除数据不删除表结构,truncate 删除后将重建索引(新插入数据后id从0开始记起),而 delete不会删除索引 (新插入的数据将在删除数据的索引后继续增加),drop语句将删除表的结构包括依赖的约束,触发器,索引等;
    3.drop和truncate删除时不记录MySQL日志,不能回滚,delete删除会记录MySQL日志,可以回滚;
    4.返回值:delete 操作后返回删除的记录数,而 truncate 返回的是0或者-1(成功则返回0,失败返回-1)

Read More

sql注入

  sql注入是常见的攻击形式,通过注入sql语句,导致程序的安全以及数据库安全。
  sql注入一般见效于拼接sql语句中,通过破坏输入规则,插入期望的sql语句,以此达到所要达到的目的。
  两个例子:

1.查找sql注入,一般用于登录界面。
拼接sql语句:
    String sql = "SELECT * FROM student where username ='"+username+"' AND password = '"+password+"';" 
//AND 运行优先级高于 OR
注入sql语句:
    username = "123";
    password = "'or '1'='1";
SQL最终语句: 
    SELECT * FROM student where username ='123' AND password = '' or '1'='1';
因而可以将所有数据查出,造成登录成功。
2.在查询操作中插入删除操作。
拼接sql语句:
    String sql = "SELECT * FROM student where username ='"+username+"' AND password = '"+password+"';" 

注入sql语句:
    username = "123";
    password = "'; DELETE FROM student where '1'='1"
SQL最终语句:
    SELECT * FROM student where username ='123' AND password =''; DELETE FROM student where '1'='1';
注:该操作是批处理操作,但是java 中mysql执行方法execute不支持此操作。

  因此为了避免sql注入,我们需要使用参数化sql语句,即预编译好的sql语句,除此之外做好用户输入数据的验证与过滤操作,以及最小化用户权限。即使是参数化sql语句,我们也要避免拼接sql语句,否则依旧会有被sql注入的可能。
  这里主要是学习参数化sql语句,其他的会在后面项目中学习。
  参数化sql语句就是使用占位符?代替部分参数,通过prepareStatement(String sql),创建一个preparedStatement,随后使用不带参数的execute/executeUpdate/executeQuery命令执行操作,不过在这之前通过preparedStatement对象的setInt与setString方法对?占位参数赋值,其中第一个参数为int型,表示第几个占位符,后面则为要赋的值。下面展示一个例子:

Connection conn = DriverManager.getConnection(url,username,password);
String sql = "INSERT INTO student(name,id_card) VALUES(?,?);";
PreparedStatement pstm = conn.prepareStatemnet(sql);
pstm.setString(1,"1234");
pstm.setString(2,"1234");
pstm.executeUpdate();
ResultSetMetaData rsmd = rs.getMetaData();int columnCount = rsmd.getColumnCount();这个可以获取字段数目,当我们忘记原本的数据库字段数时使用。

Read More

插入数据

  插入单行数据命令:

INSERT INTO 表名(字段名1,字段名2...) VALUES(值1,值2...);

  插入多行数据命令:

INSERT INTO 表名(字段名1,字段名2...) VALUES(a1,a2...),(b1,b2...),...;

Read More

类型

  Varchar与char区别:

Varchar 是可变长,需要字节存储长度,不大于255,需要1字节,特殊的如果表格使用ROW_FORMAT=FIXED,则变为固定长度。一般不能直接设定最大值,虽然在mysql中看是变长,但是对于内存来说是直接开辟全部长度,以避免放不下情况,会浪费资源,同时Varchar在更新时,也会出现页内存储不够的情况,MylSAM会将行拆成不同的片段存储,InnoDB则需要分裂页来使行可以放进页内,允许最大长度为65535个字节,同时列共享(相加)。
char 是固定长度,不够部分用空格补充,允许最大长度为255个字符,

  AUTO_INCREMENT 自增,所修饰字段具备如下特性:

1、字段不能为null,即设定NOT NULL;
2、字段必须有唯一索引,即不允许有重复值,UNIQUE标识为唯一索引,不允许重复,但是可以为空,主键索引,通过设置主键自动创建,其不允许重复同时不允许为空,所以一般该字段设定为主键或者是唯一不为空字段;
3、字段类型必须为整型;
4、字段达到最大值时,失效;

  主键创建可以在字段声明时利用PRIMARY KEY设定,也可以在字段最后加入PRIMARY KEY(‘字段1’,‘字段2’),我认为应该使用后者,当然如果只设定一个字段为主键可以使用前者,但是后者舍得主键与字段分开,便于阅读,同时便于确定主键。主键只能指定一个,但是可以包括多个字段。

1、CREATE TABLE table_1(
    'id' int NOT NULL PRIMARY KEY AUTO_INCREMENT,
    'name' varchar(10) NOT NULL
)ENGINE=InnoDB AUTO_INCREMENT=7 DEAFAULT CHARSET=utf8;
2、CREATE TABLE table_2(
    'id' int NOT NULL ATUO_INCREMENT,
    'name' varchar(10) NOT NULL,
    PRIMARY KEY('id')
)ENGINE=InnoDB AUTO_INCREMENT=7 DEAFALT CHARSET=utf8;

  唯一键UNIQUE KEY,设定与PRIMARY KEY差不多,一个是声明字段时加UNIQUE,另一个在最后使用UNIQUE KEY ‘标识名称’ (‘字段名1’,‘字段名2’…),也可以在修改表命令中使用ALTER TABLE <数据表名> ADD CONSTRAINT <唯一约束名> UNIQUE<列名>,也可ALTER TABLE ‘表名’ ADD unique(‘字段名’),或者create unique index ‘名称’ on ‘表名’ (‘字段名’),删除表使用ALTER TABLE <数据表名> DROP INDEX <唯一约束名>;

1、创建UNIQUE KEY
a. CREATE TABLE table_1(
    'id' int NOT NULL PRIMARY KEY AUTO_INCREMENT,
    'name' varchar(10) NOT NULL,
    'id_card' char(13) NOT NULL UNIQUE,
)ENGINE=InnoDB AUTO_INCREMENT=7 DEAFAULT CHARSET=utf8;
b. CREATE TABLE table_1(
    'id' int NOT NULL PRIMARY KEY AUTO_INCREMENT,
    'name' varchar(10) NOT NULL,
    'id_card' char(13) NOT NULL,
    UNIQUE KEY 'id_unique' ('id_card')
)ENGINE=InnoDB AUTO_INCREMENT=7 DEAFAULT CHARSET=utf8;
c. CREATE TABLE table_1(
    'id' int NOT NULL PRIMARY KEY AUTO_INCREMENT,
    'name' varchar(10) NOT NULL,
    'id_card' char(13) NOT NULL
)ENGINE=InnoDB AUTO_INCREMENT=7 DEAFAULT CHARSET=utf8;
   ALTER TABLE table_1 ADD CONSTRAINT 'indexID' UNIQUE 'id_card';
   或者 CREATE UNIQUE INDEX 'indexID' on 'table_1' ('id_card');
3、删除唯一索引
ALTER TABLE table_1 DROP INDEX 'indexID';

Read More

Hexo在post文件夹中子文件夹中创建文档

  随着hexo创建博客增多,我发现如果都是hexo new 文件时,所有文件都会出现在_post文件夹中,然后就无法很好地整理与查找文件了,因此需要通过子文件夹来进行分类,所以需要在创建时就将其分文件夹创建。

hexo new [post] -p 子文件夹/文件名 "文件题目"
[]是说创建什么模式,一般有post、draft、page模式,当使用post是会在/source/_post文件夹下创建,而draft则是在source/_draft文件夹下创建,page则是在source下创建。
附:
Usage: hexo new [layout] <title>

Description:
Create a new post.

Arguments:
  layout  Post layout. Use post, page, draft or whatever you want.
  title   Post title. Wrap it with quotations to escape.

Options:
  -p, --path     Post path. Customize the path of the post.
  -r, --replace  Replace the current post if existed.
  -s, --slug     Post slug. Customize the URL of the post.

Read More

脚本延时变量

  在进行编写脚本时,发现了延时变量与非延时变量,记录一下。一般if语句被认为是一行命令,而if中往往有几行命令,此时命令可以被认为是并行的,但是如果使用了延时扩展,就如同被认为不同命令,相继执行。

setlocal enabledelayedexpansion ::开启延时扩展
set a = 2
if %a% =;=2 (::括号前要有空格

    set a=3
    echo !a!::当使用!!才会变成延时变量
    echo %a%
    ::此时!a!输出3,而%a%输出2。

)
pause

Read More

Hexo代码块问题

  这次问题是配置代码块高亮问题:1.可以使用prism插件;2.可以使用hexo现在自带的prismjs,具体如何配置搜索便有。
  我要提醒我自己的是markdown可以使用```来进行代码标识,但是记住一定要间隔一行,否则容易不识别,这个是一个大问题,也是我一直不成功的原因,现在终于知道了。

Read More