http://blog.csdn.net/yerenyuan_pku/article/details/71699515

MyBatis框架的架构

MyBatis框架的架构如下图: 

下面作简要概述:

  1. SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句,此文件需要在SqlMapConfig.xml中加载。
  2. 通过mybatis环境等配置信息构造SqlSessionFactory(即会话工厂)。
  3. 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
  4. mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  5. MappedStatement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个MappedStatement对象,sql的id即是MappedStatement的id
  6. MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql前将输入的java对象映射至sql中,输入参数映射就是JDBC编程中对preparedStatement设置参数。
  7. MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于JDBC编程中对结果的解析处理过程。

MyBatis入门

mybatis下载

mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases。大家可从该地址下载mybatis最新框架。 
本人下载的是mybatis-3.2.7,其目录结构为: 

开发需求

现在我们明确需求,即实现以下功能:

  1. 根据用户id查询一个用户信息
  2. 根据用户名称模糊查询用户信息列表
  3. 添加用户
  4. 更新用户
  5. 删除用户

MyBatis入门程序配置

【第一步】,使用Eclipse创建一个普通的Java工程,例如mybatis-day01。 
【第二步】,加入Jar包。工程所需加入的Jar包有mybatis核心包、依赖包和MySQL数据驱动包。如下: 
 
【第三步】,在classpath下创建日志记录文件——log4j.properties。我们可在mybatis-day01工程下新建一个config源码包,并在该源码包下创建一个日志记录文件——log4j.properties 
 
log4j.properties文件的内容如下:

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

mybatis默认使用log4j作为输出日志信息。 
【第四步】,在classpath下创建SqlMapConfig.xml文件。我们同样可在config源码包下创建该文件 
 
其内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 和spring整合后environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="yezi" /> </dataSource> </environment> </environments> </configuration>

SqlMapConfig.xml是mybatis的核心配置文件,以上文件的配置内容为数据源、事务管理。 
注意:等后面mybatis和Spring两个框架整合之后,environments的配置将被废除。 
【第五步】,创建一个po类——User.java。我们可在src目录下新建一个名为cn.itheima.mybatis.po的包,并在该包下创建一个po类——User.java 
 
po类作为mybatis进行sql映射使用,po类通常与数据库表对应,User.java文件的内容如下:

public class User {private int id;private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } }

【第六步】,在classpath下的sqlmap目录下创建sql映射文件user.xml 
 
user.xml文件的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test"> </mapper>

namespace:即命名空间,其用于隔离sql语句(即不同sql映射文件中的两个相同id的sql语句如何来区分),这是当前的作用,后面会讲另一层非常重要的作用。 
【第七步】,加载映射文件。mybatis框架需要加载映射文件,将user.xml添加在SqlMapConfig.xml中,如下: 

故须在SqlMapConfig.xml配置文件中添加如下配置信息:

<mappers><!-- resource是基于classpath来查找的 --><mapper resource="sqlmap/user.xml"/> </mappers>

MyBatis入门程序测试——根据id查询用户信息

在user.xml映射文件中添加如下配置:

<!-- 根据id获取用户信息 -->
<select id="getUserById" parameterType="int" resultType="cn.itheima.mybatis.po.User"> select * from user where id=#{id}; </select>
  • parameterType:查询参数的数据类型,即定义输入到sql中的映射类型。
  • resultType:查询结果的数据类型,如果是pojo则应该给出全路径。
  • #{id}表示使用PreparedStatement设置占位符号并将输入变量id传到sql中。说白点,#{}作用就是占位符,相当于JDBC中的?

接着在src目录下新建一个名为cn.itheima.mybatis.first的包,并在该包下创建一个MybatisTest单元测试类,紧接着在该类中编写如下一个但单元测试方法:

public class MybatisTest {@Testpublic void getUserById() throws IOException { // 第一步,创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 第二步,加载配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 第三步,创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 第四步,创建SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 第五步,使用SqlSession对象执行查询,得到User对象 // 第一个参数:执行查询的StatementId User user = sqlSession.selectOne("getUserById", 10); // 第六步,打印结果 System.out.println(user); // 第七步,释放资源,每一个sqlSession就是一个连接 sqlSession.close(); } }

以上完成的需求就是根据id查询用户信息。一般来讲工厂对象一般在实际开发是单例的,并不需要频繁地创建,故getUserById()方法可优化为:

public class MybatisTest {private SqlSessionFactory sqlSessionFactory = null; // 工厂对象一般在我们的系统中是单例的 @Before public void init() throws IOException { // 第一步,创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 第二步,加载配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 第三步,创建SqlSessionFactory对象 sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); } @Test public void getUserById() throws IOException { // 第四步,创建SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 第五步,使用SqlSession对象执行查询,得到User对象 // 第一个参数:执行查询的StatementId User user = sqlSession.selectOne("getUserById", 10); // 第六步,打印结果 System.out.println(user); // 第七步,释放资源,每一个sqlSession就是一个连接 sqlSession.close(); } }
  • 1

根据用户名称模糊查询用户信息列表

现在我就来完成第二个需求——根据用户名称模糊查询用户信息列表。 
一开始我在user.xml映射文件中添加如下配置:

<select id="getUserByName" parameterType="string" resultType="cn.itheima.mybatis.po.User">SELECT * FROM `user` WHERE username LIKE #{username} </select>
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如果查询结果返回的是List集合,那么resultType只需要设置为List集合中的一个元素的数据类型即可。 
接着在MybatisTest单元测试类编写如下单元测试方法:

@Test
public void getUserByName() {// 创建一个SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();// 执行查询 List<User> list = sqlSession.selectList("getUserByName", "%张%"); for (User user : list) { System.out.println(user); } // 释放资源 sqlSession.close(); }
  • 1

运行以上方法,Eclipse控制台打印如下: 

实际开发中建议使用#{}占位符这种方式,因为这样可以防止SQL注入。除了以上这种方式外,在此我还介绍第二种方式,即在user.xml映射文件中添加如下配置:

<select id="getUserByName" parameterType="string" resultType="cn.itheima.mybatis.po.User">SELECT * FROM `user` WHERE username LIKE '%${value}%' </select>

${value}表示使用参数将${value}替换,做字符串的拼接,${}为字符串拼接指令。注意:如果是取简单数据类型的参数,括号中的值必须为value。 
如此一来,MybatisTest单元测试类中的getUserByName()方法应修改为:

@Test
public void getUserByName() {// 创建一个SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();// 执行查询 List<User> list = sqlSession.selectList("getUserByName", "张"); for (User user : list) { System.out.println(user); } // 释放资源 sqlSession.close(); }
  • 1

运行以上方法,Eclipse控制台打印如下: 

很明显这种方式在实际开发中是不建议使用的,因为无法防止SQL注入。

总结

#{}和${}

#{}:表示一个占位符号,可以很好地去避免sql注入。其原理是将占位符位置的整个参数和sql语句两部分提交给数据库,数据库去执行sql语句,去表中匹配所有的记录是否和整个参数是否一致。 
#{}要获取输入参数的值:

  • 如果输入参数是简单数据类型,则#{}中可以写value或其它名称。
  • 如果输入参数是pojo对象类型,则#{}可通过OGNL方式去获取,表达式就是属性.属性.属性....方式。

${}表示一个sql拼接符号,其原理是在向数据库发出sql之前去拼接好sql再提交给数据库执行。 
${}要获取输入参数的值:

  • 如果输入参数是简单数据类型,则${}中只能写value。
  • 如果输入参数是pojo对象类型,则${}可通过OGNL方式去获取,表达式就是属性.属性.属性....方式。

一般情况下建议使用#{},特殊情况下必须要用${},比如:

  1. 动态拼接sql中动态组成排序字段,要通过${}将排序字段传入sql中。
  2. 动态拼接sql中动态组成表名,要通过${}将表名传入sql中。

parameterType和resultType

parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。 
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。

selectOne()和selectList()方法

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常: 

selectList可以查询一条或多条记录。

添加用户

现在我就来完成第三个需求——添加用户。首先在user.xml映射文件中添加如下配置:

<insert id="insertUser" parameterType="cn.itheima.mybatis.po.User">INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
</insert>

如果输入参数是pojo,那么#{}中的名称就是pojo类中的属性(用到了对象图导航的思想),而不能随便写了。 
然后试着在MybatisTest单元测试类编写如下单元测试方法:

@Test
public void addUser() {// 创建一个SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建User对象 User user = new User(); user.setUsername("小乔"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("上海"); // 插入用户 sqlSession.insert("insertUser", user); // 释放资源 sqlSession.close(); }

运行以上方法,发现Eclipse控制台中打印: 

虽然发出了sql语句,但是事务并没将其提交,而是回滚了。故User对象是无法插入到数据库user表中的。所以addUser()单元测试方法应修改为:

@Test
public void addUser() {// 创建一个SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建User对象 User user = new User(); user.setUsername("小乔"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("上海"); // 插入用户 sqlSession.insert("insertUser", user); // 提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }
  • 1

运行以上方法,Eclipse控制台会打印: 

事务已提交,可发现数据库user表中插入一条记录。

MySQL自增主键返回

现在有这样一个需求:想要得到MySQL数据库给我们生成的主键id,即获取主键。那如何实现这个需求呢?这里要用到MySQL数据库中的一个函数:

  • LAST_INSERT_ID():返回auto_increment自增列新记录id值。该函数是在当前事务下取到你最后生成的id值,而我们应知道查询操作是没有开启事务的,增删改操作是需要开启事务的。

如此一来,需要将user.xml映射文件中的如下配置:

<insert id="insertUser" parameterType="cn.itheima.mybatis.po.User">INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
</insert>

修改为(即添加selectKey实现将主键返回):

<insert id="insertUser" parameterType="cn.itheima.mybatis.po.User"> <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>
  • 1
  • keyProperty:返回的主键存储在pojo中的哪个属性(即其对应pojo的主键属性)。获取主键,实际上是将主键取出来之后封装到了pojo的主键属性当中。
  • resultType:返回的主键是什么类型(即其对应pojo的主键的数据类型)。
  • order:selectKey的执行顺序,是相对于insert语句来说的,由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为AFTER。

最后将addUser()单元测试方法应修改为:

@Test
public void addUser() {// 创建一个SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();// 创建User对象 User user = new User(); user.setUsername("大乔"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("上海"); // 插入用户 sqlSession.insert("insertUser", user); System.out.println(user.getId()); // 提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }

运行以上方法,Eclipse控制台会打印: 

MySql使用uuid实现主键

使用uuid实现主键,需要增加通过select uuid()语句得到uuid值作为主键。所以需要将user.xml映射文件中id为insertUser的Statement改置为:

<insert id="insertUser" parameterType="cn.itheima.mybatis.po.User">
<selectKey resultType="java.lang.String" order="BEFORE"
keyProperty="id">select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>

因为是使用uuid做主键,所以应该先生成主键然后再插入数据,此时order属性的值应是BEFORE。

删除用户

现在我就来完成第四个需求——删除用户。首先在user.xml映射文件中添加如下配置:

<!-- 删除用户 -->
<delete id="deleteUser" parameterType="int"> DELETE FROM `user` WHERE id=#{id1} </delete>
  • 1

然后在MybatisTest单元测试类编写如下单元测试方法:

@Test
public void deleteUser() {// 创建一个SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 删除用户 sqlSession.delete("deleteUser", 29); // 提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }
  • 1
  • 2

更新用户

现在我就来完成第五个需求——修改用户信息。首先在user.xml映射文件中添加如下配置:

<!-- 修改用户信息 -->
<update id="updateUser" parameterType="cn.itheima.mybatis.po.User"> UPDATE `user` set username=#{username} WHERE id=#{id} </update>

然后在MybatisTest单元测试类编写如下单元测试方法:

@Test
public void updateUser() {// 创建一个SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建一个User对象 User user = new User(); user.setUsername("张角"); user.setId(10); // 更新用户 sqlSession.update("updateUser", user); // 提交事务 sqlSession.commit(); sqlSession.close(); }

MyBatis解决了JDBC编程的问题

还记得MyBatis框架的学习(一)——MyBatis介绍一文中使用JDBC编程所带来的问题吗?现在使用MyBatis这个框架就可以解决JDBC编程所带来的这些问题。

  1. 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。 
    解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接。
  2. Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。 
    解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
  3. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。 
    解决: MyBatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
  4. 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。 
    解决: MyBatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

MyBatis与Hibernate的不同之处

MyBatis和Hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过MyBatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。 
MyBatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是MyBatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。 
Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用Hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。 
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

我个人总结的MyBatis与Hibernate这两个框架的不同之处:

  • MyBatis学习成本低,入门门槛低。MyBatis需要程序员自己写sql,对sql修改和优化就比较灵活。MyBatis是不完全的ORM框架,MyBatis需要程序员编写sql,但是MyBatis也存在映射(输入映射、输出映射)适用场景:需求变化较快的项目开发,比如互联网项目、电商。
  • Hibernate学习成本高,入门门槛高,Hibernate是ORM框架,不需要程序员编写sql,自动根据对象映射生成sql。适用场景:需求固定的中小型项目,如OA系统、ERP系统。

企业在技术选型上应考虑各个技术框架的特点去进行选型,企业要根据人力、物力等资源去衡量,以节省成本利润最大化为目标进行选型。 
至此,我们就算入门MyBatis了。读者如需查看源码,可参考MyBatis框架的学习(二)——MyBatis架构与入门

转载于:https://www.cnblogs.com/telwanggs/p/6911694.html

(转)MyBatis框架的学习(二)——MyBatis架构与入门相关推荐

  1. (转)MyBatis框架的学习(七)——MyBatis逆向工程自动生成代码

    http://blog.csdn.net/yerenyuan_pku/article/details/71909325 什么是逆向工程 MyBatis的一个主要的特点就是需要程序员自己编写sql,那么 ...

  2. (转)MyBatis框架的学习(六)——MyBatis整合Spring

    http://blog.csdn.net/yerenyuan_pku/article/details/71904315 本文将手把手教你如何使用MyBatis整合Spring,这儿,我本人使用的MyB ...

  3. (转)MyBatis框架的学习(一)——MyBatis介绍

    http://blog.csdn.net/yerenyuan_pku/article/details/71699343 MyBatis介绍 MyBatis本是apache的一个开源项目iBatis,2 ...

  4. (转)MyBatis框架的学习(三)——Dao层开发方法

    http://blog.csdn.net/yerenyuan_pku/article/details/71700957 使用MyBatis开发Dao层,通常有两个方法,即原始Dao开发方法和Mappe ...

  5. (转)MyBatis框架的学习(五)——一对一关联映射和一对多关联映射

    http://blog.csdn.net/yerenyuan_pku/article/details/71894172 在实际开发中我们不可能只是对单表进行操作,必然要操作多表,本文就来讲解多表操作中 ...

  6. (转)MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql

    http://blog.csdn.net/yerenyuan_pku/article/details/71893689 前面对MyBatis框架的学习中,我们对Mapper.xml映射文件多少有些了解 ...

  7. 【Mybatis框架】从零开始学Mybatis框架——使用示例

    一.数据库SQL 命令 1.创建数据库,并指定编码 Create database ssm default character set utf8 2.创建表 Create table 表名(列名类型约 ...

  8. Mybatis源码分析之(一)搭建一个mybatis框架(写一个mybatis的Demo)

    数据库工作: 首先准备工作,安装mysql,并且新建一张t_demo表 CREATE TABLE `t_demo` (`name` varchar(255) COLLATE utf8_unicode_ ...

  9. Mybatis源码学习二(一级缓存)

    一级缓存流程 一级缓存有效的因素 一级缓存有效测试 public class User {private Integer id;private String name;public Integer g ...

最新文章

  1. 关于Synchronized研伸扩展
  2. sql注入——day02
  3. 中山大学 精品课程C++ 视频教学 共51讲
  4. esxi虚拟化集群_ProxmoxVE 之集群安装(V5.2)
  5. Java——Arrays类操作数组的工具类
  6. Flex的动画效果与变换(1)
  7. mysql配置文件my.cnf解析
  8. iPhone SDK开发基础之 OpenFlow编程
  9. 假期最后一天,出差赶到天津
  10. 2016年WiFi行业技术发展趋势解析
  11. 这可能不只是一篇面经
  12. 使用360文件粉碎机卸载北信源软件
  13. Android安全测试框架Drozer(安装篇)
  14. 微型计算机存储容量2mb,在微型计算机中,存储容量为2MB是指
  15. 如何用easyx播放音乐,插入图片
  16. Adobe Photoshop 2021 22.1.1.138中文版(win/mac)
  17. 亲身实践已解决:Mysql Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT
  18. 爱情小筑 v3.1 build 2002.07.26 免费下载
  19. 英语中的现在分词和过去分词
  20. 编程基础——鱼龙混杂来一波

热门文章

  1. android删除wifi配置,[RK3288][Android6.0] WiFi之无线网络配置的忘记(移除)过程
  2. python 字符串删除重复_leetcode No.1047 删除字符串中的所有相邻重复项
  3. 如何给小朋友解释单摆运动_单摆的教案
  4. (21)xilinx PCIE 开发方法(学无止境)
  5. (12)VHDL组合逻辑
  6. (10)verilog语言编写SPI发送
  7. 水经注叠加cad_如何下载等高线并在CAD中与卫星影像叠加
  8. java instance关键字_Java中instanceof关键字和isInstance()方法的区别是什么
  9. mysql建立索引的优缺点|创建索引alter或create索引分类(PRIMARY KEY,UNIQUE KEY,FULLTEXT,INDEX)作用查看索引show index from table
  10. 内核并发控制---信号量 (来自网易)