tkmybatis是在mybatis框架的基础上提供了很多工具,让开发更加高效,下面来看看这个框架的基本使用,后面会对相关源码进行分析,感兴趣的同学可以看一下,挺不错的一个工具

实现对员工表的增删改查的代码

java的dao层接口public interfaceWorkerMapperextendsMapper{

}

xml映射文件<?xml version="1.0" encoding="UTF-8"?>

实体对象@Table(name = "worker")

public classWorker{

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Integer id;

@Column(name = "worker_id")

private String workerId;

private String name;

@Column(name = "org_id")

private Integer orgId;

private String status;

@Column(name = "role_id")

private Integer roleId;

// getters and setters ...

}

以上就是实现对Worker进行增删改查的所有代码,包括选择性更新、插入、删除等,所有的方法列表如下

以后对表字段的添加或修改只需要更改实体对象的注解,不需要修改xml映射文件,如将worker_id改成worker_no@Column(name = "worker_no")

private String workerNo;

数据源的配置,只需要将org.mybatis.spring.mapper.MapperScannerConfigurer改成tk.mybatis.spring.mapper.MapperScannerConfigurer,然后加一个属性

,也可不加,因为框架提供了默认实现

mappers=tk.mybatis.mapper.common.Mapper

用这个库之后写代码感觉在飞…….如果只是简单的了解此框架到这里就可以了,下面是对框架实现原理的分析

原理的简单分析

此框架为我们实现这些功能所有的改动都在Mapper层面,所有的Mapper都继承了tk.mybatis.mapper.common.Mapperpublic interfaceWorkerMapperextendsMapper{}

Mapper接口的声明如下,可以看到Mapper接口实现了所有常用的方法public interfaceMapperextends

BaseMapper,

ExampleMapper,

RowBoundsMapper,

Marker{

}

看一下完整的UML图,太大了,可以用新窗口打开,放大之后再看

这里选择一个接口:SelectOneMapper接口,对于源码进行简单分析,此接口声明如下:public interface SelectOneMapper{

/**

* 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号

*

*@paramrecord

*@return

*/

@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")

T selectOne(T record);

}

@SelectProvider是mybatis3之后提供的,用于灵活的设置sql来源,这里设置了服务提供类和方法,但这个库并没有直接用method指定的方法来返回sql,而是在运行时进行解析的,代码如下public classBaseSelectProviderextendsMapperTemplate{

publicStringselectOne(MappedStatement ms){

Class> entityClass = getEntityClass(ms);

//修改返回值类型为实体类型

setResultType(ms, entityClass);

StringBuilder sql = new StringBuilder();

sql.append(SqlHelper.selectAllColumns(entityClass));

sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));

sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));

return sql.toString();

}

}

到这里我们就大概知道了这个库为我们提供便利的原理了,总的来说就是这个库帮我们提供了对表的基本操作的sql,帮我们省了很多工作量,而且维护起来也很方便,否则我们的xml文件动不动就几百行甚至上千行

对源码的探索不能到这里停止,最起码要分析到与另一个框架的整合点

我们知道,mybatis的mapper接口是在启动的时候被框架以JdkProxy的形式封装了的,具体对应的类是MapperFactoryBean,这个类中有一个checkDaoConfig()方法,是从父类继承并重写了该方法,继承结构如下MapperFactoryBean -> SqlSessionDaoSupport -> DaoSupport

这里的DaoSupport就是spring提供的Dao的抽象,代码如下public abstract classDaoSupportimplementsInitializingBean{

// spring 完成属性设置后会调用此方法

@Override

publicfinalvoidafterPropertiesSet()throwsIllegalArgumentException, BeanInitializationException{

// 这里提供了接口供子类去实现

checkDaoConfig();

// Let concrete implementations initialize themselves.

try {

initDao();

}

catch (Exception ex) {

throw new BeanInitializationException("Initialization of DAO failed", ex);

}

}

protectedabstractvoidcheckDaoConfig()throwsIllegalArgumentException;

protectedvoidinitDao()throwsException{

}

}

框架自定义的MapperFactoryBean重写了checkDaoConfig()方法,完成对所有sql语句的设置,代码如下@Override

protectedvoidcheckDaoConfig(){

super.checkDaoConfig();

//通用Mapper

if (mapperHelper.isExtendCommonMapper(getObjectType())) {

//这里去处理该类所对应的MappedStatement,封装在helper类中处理

mapperHelper.processConfiguration(getSqlSession().getConfiguration(), getObjectType());

}

}

MapperHelper的processConfiguration方法如下publicvoidprocessConfiguration(Configuration configuration, Class> mapperInterface){

String prefix;

if (mapperInterface != null) {

prefix = mapperInterface.getCanonicalName();

} else {

prefix = "";

}

for (Object object : new ArrayList(configuration.getMappedStatements())) {

if (object instanceof MappedStatement) {

MappedStatement ms = (MappedStatement) object;

//检查这个MappedStatement是否属于此映射对象

if (ms.getId().startsWith(prefix) && isMapperMethod(ms.getId())) {

if (ms.getSqlSource() instanceof ProviderSqlSource) {

//去设置该statement的sql语句

setSqlSource(ms);

}

}

}

}

}

设置sql的逻辑,提供了几种不同类型的sqlsourcepublic void setSqlSource(MappedStatement ms) throws Exception {

if (this.mapperClass == getMapperClass(ms.getId())) {

throw new RuntimeException("请不要配置或扫描通用Mapper接口类:" + this.mapperClass);

}

Method method = methodMap.get(getMethodName(ms));

try {

//第一种,直接操作ms,不需要返回值

if (method.getReturnType() == Void.TYPE) {

method.invoke(this, ms);

}

//第二种,返回SqlNode

else if (SqlNode.class.isAssignableFrom(method.getReturnType())) {

SqlNode sqlNode = (SqlNode) method.invoke(this, ms);

DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode);

setSqlSource(ms, dynamicSqlSource);

}

//第三种,返回xml形式的sql字符串

else if (String.class.equals(method.getReturnType())) {

String xmlSql = (String) method.invoke(this, ms);

SqlSource sqlSource = createSqlSource(ms, xmlSql);

//替换原有的SqlSource

setSqlSource(ms, sqlSource);

到这里整个sql的获取流程就分析完了,本人用这个库写过一个小项目,确实节省了开发的工作量,而且DAO层的结构更加清晰简洁了

关于mybatis新特性

从3.4.0开始,mybatis提供对外部表的alias引用方法,多表联合查询就方便多了,我们先看原始的方式是怎样做的select a.id,a.name,b.bid,b.bname .....

from user a

left join room b

原始的方式是将所有的表字段列出来,再来看用新特性怎样做

select id="selectUsers" resultType="map">

select

,

from user t1

left join room t2

这里主要就是对基本的sql进行了复用,如果对表进行了修改只要在原始的sql节点修改就可以了,就算是5个表的联合查询,sql也是清晰易懂,维护起来会更轻松

新版本的mybatis对于对象映射也提供了更友好的方式,直接使用外部的ResultMap再加上查询语句中的别名就映射完成了

更进一步

敏锐的程序员可能会提出问题,如当多表查询的时候可能会存在字段名称相同的情况,这里的解决方案是给include添加另一个属性

包含prefix的sqlNode如下

${alias}.ID as ${prefix}ID,

${alias}.WORKER_ID as ${prefix}WORKER_ID,

${alias}.NAME as ${prefix}NAME,

${alias}.ZB_ROLE_ID as ${prefix}ZB_ROLE_ID,

${alias}.ORG_ID as ${prefix}ORG_ID,

${alias}.STATUS as ${prefix}STATUS

如果说觉得手动写包含alias和prefix的字段麻烦,可以用,mybatis代码生成器的插件的方式实现,我自己写了一个生成器的插件,可以代码再这里,仅供参考

通用Service类/**

* Created by Kaiwen

*/

@Service

public abstract classCommonServiceImplimplementsCommonService{

/**

* 泛型注入

*/

@Autowired

private Mapper mapper;

publicT selectByPrimaryKey(PK entityId){

return mapper.selectByPrimaryKey(entityId);

}

publicintdeleteByPrimaryKey(PK entityId){

return mapper.deleteByPrimaryKey(entityId);

}

publicintinsert(T record){

return mapper.insert(record);

}

publicintinsertSelective(T record){

return mapper.insertSelective(record);

}

publicintupdateByPrimaryKeySelective(T record){

return mapper.updateByPrimaryKeySelective(record);

}

publicintupdateByPrimaryKey(T record){

return mapper.updateByPrimaryKey(record);

}

publicList selectByExample(Example example){

return mapper.selectByExample(example);

}

}

注入方式区别

mappers=tk.mybatis.mapper.common.Mapper

<

实体类package com.jjshome.esf.common.entity.school;

import java.util.Date;

import javax.persistence.*;

@Table(name = "XQ_SCHOOL_AREA")

public classSchoolArea{

/**

* 主键ID

*/

@Id

@Column(name = "ID")

private Integer id;

/**

* 城市编码

*/

@Column(name = "CITY_CODE")

private String cityCode;

/**

* 学区名称

*/

@Column(name = "NAME")

private String name;

/**

* 学区名称拼音

*/

@Column(name = "NAME_SPELL")

private String nameSpell;

/**

* 状态,1:正常,0:删除

*/

@Column(name = "STATUS")

private Byte status;

/**

* 添加人

*/

@Column(name = "CREATE_ID")

private String createId;

@Transient

private Integer primaryCount; //小学数量

@Transient

private Integer middleCount; //初中数量

@Transient

private Integer highCount;//高中数量

TK mybatis Mapper文件内容<?xml version="1.0" encoding="UTF-8" ?>

extends="com.jjshome.esf.core.dao.school.ISchoolInfoDAO.SchoolInfo">

SELECT A.*, C.NAME AS CITY_NAME,

(SELECT COUNT(*) FROM XQ_SCHOOL_INFO B WHERE A.ID=B.AREA_ID AND B.TYPE='553' AND B.STATUS = 1 ) AS PRIMARY_COUNT,

(SELECT COUNT(*) FROM XQ_SCHOOL_INFO B WHERE A.ID=B.AREA_ID AND B.TYPE='554' AND B.STATUS = 1 ) AS MIDDLE_COUNT,

(SELECT COUNT(*) FROM XQ_SCHOOL_INFO B WHERE A.ID=B.AREA_ID AND B.TYPE='555' AND B.STATUS = 1 ) AS HIGH_COUNT

FROM XQ_SCHOOL_AREA A

LEFT JOIN YW_CITY_SETTING C ON A.CITY_CODE = C.CODE

A.NAME LIKE CONCAT('%',#{NAME},'%')

A.CITY_CODE = #{areaCityCode}

( A.NAME LIKE CONCAT('%',#{keywords},'%')

)

SELECT

*

FROM

XQ_SCHOOL_AREA

WHERE

1=1

AND CITY_CODE=#{cityId}

AND (NAME like CONCAT(#{key},'%' ) or NAME_SPELL like CONCAT(#{key},'%' ))

AND

STATUS=1

limit #{pageSize}

SELECT A.* ,B.NAME AS SCHOOL_AREA_NAME ,C.NAME AS CITY_NAME,D.NAME AS AREA_NAME FROM XQ_SCHOOL_INFO A

LEFT JOIN XQ_SCHOOL_AREA B ON A.AREA_ID = B.ID

LEFT JOIN YW_CITY_SETTING C ON A.CITY_CODE = C.CODE

LEFT JOIN YW_CITY_SETTING D ON A.AREA_CODE = D.CODE

WHERE A.STATUS = 1 AND B.STATUS =1

AND A.AREA_ID = #{areaId}

AND

A.TYPE IN

#{item}

AND A.NAME LIKE CONCAT('%',#{name},'%')

普通mybatisMapper文件<?xml version="1.0" encoding="UTF-8" ?>

ID,

NAME,

NAME_SPELL,

ALIAS,

ALIAS_SPELL,

TYPE,

AREA_ID,

CITY_CODE,

AREA_CODE,

ADDR,

START_TIME,

MOTTO,

WEB_SITE,

PHONE,

FEATURE,

LNG,

LAT,

UNIT_PRICE,

SALE_PRICE,

NATURE_TYPE,

NATURE_CITY,

SCHOOL_DEGREE,

ENROL_DEGREE,

IMG_DEGREE,

STATUS,

CREATE_ID,

CREATE_DATE,

UPDATE_ID,

UPDATE_DATE,

SALE_COUNT,

SALE_COUNT

SELECT

i.*,

yc.NAME as 'CITY_NAME',

ya.NAME as 'AREA_NAME',

xq.NAME as 'SCHOOL_DISTRICT_NAME'

FROM

XQ_SCHOOL_INFO i

LEFT JOIN YW_CITY_SETTING yc ON i.CITY_CODE = yc.CODE

LEFT JOIN YW_CITY_SETTING ya ON i.AREA_CODE = ya.CODE

LEFT JOIN XQ_SCHOOL_AREA xq ON i.AREA_ID = xq.ID

WHERE

i.ID = #{id,jdbcType=INTEGER}

UPDATE

XQ_SCHOOL_INFO

SET

STATUS = 0,

UPDATE_ID = #{updateId},

UPDATE_DATE = NOW()

WHERE

ID = #{id,jdbcType=INTEGER}

UPDATE

XQ_SCHOOL_INFO

SET

STATUS = 0,

UPDATE_ID = #{updateId},

UPDATE_DATE = NOW()

WHERE

ID IN (${ids})

update XQ_SCHOOL_INFO

SET AREA_ID = NULL,

UPDATE_DATE = NOW()

WHERE

ID = #{id}

SELECT LAST_INSERT_ID()

INSERT INTO XQ_SCHOOL_INFO

(NAME,

NAME_SPELL,

ALIAS,

ALIAS_SPELL,

TYPE,

AREA_ID,

CITY_CODE,

AREA_CODE,

ADDR,

START_TIME,

MOTTO,

WEB_SITE,

PHONE,

FEATURE,

LNG,

LAT,

UNIT_PRICE,

SALE_PRICE,

NATURE_TYPE,

NATURE_CITY,

SCHOOL_DEGREE,

ENROL_DEGREE,

IMG_DEGREE,

STATUS,

CREATE_ID,

CREATE_DATE,

UPDATE_ID,

UPDATE_DATE)

VALUES

(#{name,jdbcType=VARCHAR},

#{nameSpell,jdbcType=VARCHAR},

#{alias,jdbcType=VARCHAR},

#{aliasSpell,jdbcType=VARCHAR},

#{type,jdbcType=INTEGER},

#{areaId,jdbcType=INTEGER},

#{cityCode,jdbcType=VARCHAR},

#{areaCode,jdbcType=VARCHAR},

#{addr,jdbcType=VARCHAR},

#{startTime,jdbcType=DATE},

#{motto,jdbcType=VARCHAR},

#{webSite,jdbcType=VARCHAR},

#{phone,jdbcType=VARCHAR},

#{feature,jdbcType=VARCHAR},

#{lng,jdbcType=DECIMAL},

#{lat,jdbcType=DECIMAL},

#{unitPrice},

#{salePrice},

#{natureType,jdbcType=INTEGER},

#{natureCity,jdbcType=INTEGER},

#{schoolDegree,jdbcType=INTEGER},

#{enrolDegree,jdbcType=INTEGER},

#{imgDegree,jdbcType=INTEGER},

#{status,jdbcType=TINYINT},

#{createId,jdbcType=VARCHAR},

#{createDate,jdbcType=DATE},

#{updateId,jdbcType=VARCHAR},

#{updateDate,jdbcType=DATE})

SELECT LAST_INSERT_ID()

INSERT INTO XQ_SCHOOL_INFO

NAME,

NAME_SPELL,

ALIAS,

ALIAS_SPELL,

TYPE,

AREA_ID,

CITY_CODE,

AREA_CODE,

ADDR,

START_TIME,

MOTTO,

WEB_SITE,

PHONE,

FEATURE,

LNG,

LAT,

UNIT_PRICE,

SALE_PRICE,

NATURE_TYPE,

NATURE_CITY,

SCHOOL_DEGREE,

ENROL_DEGREE,

IMG_DEGREE,

STATUS,

CREATE_ID,

CREATE_DATE,

UPDATE_ID,

UPDATE_DATE,

#{name,jdbcType=VARCHAR},

#{nameSpell,jdbcType=VARCHAR},

#{alias,jdbcType=VARCHAR},

#{aliasSpell,jdbcType=VARCHAR},

#{type,jdbcType=INTEGER},

#{areaId,jdbcType=INTEGER},

#{cityCode,jdbcType=VARCHAR},

#{areaCode,jdbcType=VARCHAR},

#{addr,jdbcType=VARCHAR},

#{startTime,jdbcType=DATE},

#{motto,jdbcType=VARCHAR},

#{webSite,jdbcType=VARCHAR},

#{phone,jdbcType=VARCHAR},

#{feature,jdbcType=VARCHAR},

#{lng,jdbcType=DECIMAL},

#{lat,jdbcType=DECIMAL},

#{unitPrice},

#{salePrice},

#{natureType,jdbcType=INTEGER},

#{natureCity,jdbcType=INTEGER},

#{schoolDegree,jdbcType=INTEGER},

#{enrolDegree,jdbcType=INTEGER},

#{imgDegree,jdbcType=INTEGER},

#{status,jdbcType=TINYINT},

#{createId,jdbcType=VARCHAR},

#{createDate,jdbcType=DATE},

#{updateId,jdbcType=VARCHAR},

#{updateDate,jdbcType=DATE},

UPDATE XQ_SCHOOL_INFO

NAME=#{name,jdbcType=VARCHAR},

NAME_SPELL=#{nameSpell,jdbcType=VARCHAR},

ALIAS=#{alias,jdbcType=VARCHAR},

ALIAS_SPELL=#{aliasSpell,jdbcType=VARCHAR},

TYPE=#{type,jdbcType=INTEGER},

AREA_ID=#{areaId,jdbcType=INTEGER},

CITY_CODE=#{cityCode,jdbcType=VARCHAR},

AREA_CODE=#{areaCode,jdbcType=VARCHAR},

ADDR=#{addr,jdbcType=VARCHAR},

START_TIME=#{startTime,jdbcType=DATE},

MOTTO=#{motto,jdbcType=VARCHAR},

WEB_SITE=#{webSite,jdbcType=VARCHAR},

PHONE=#{phone,jdbcType=VARCHAR},

FEATURE=#{feature,jdbcType=VARCHAR},

LNG=#{lng,jdbcType=DECIMAL},

LAT=#{lat,jdbcType=DECIMAL},

UNIT_PRICE=#{unitPrice},

SALE_PRICE=#{salePrice},

NATURE_TYPE=#{natureType,jdbcType=INTEGER},

NATURE_CITY=#{natureCity,jdbcType=INTEGER},

SCHOOL_DEGREE=#{schoolDegree,jdbcType=INTEGER},

ENROL_DEGREE=#{enrolDegree,jdbcType=INTEGER},

IMG_DEGREE=#{imgDegree,jdbcType=INTEGER},

STATUS=#{status,jdbcType=TINYINT},

CREATE_ID=#{createId,jdbcType=VARCHAR},

CREATE_DATE=#{createDate,jdbcType=DATE},

UPDATE_ID=#{updateId,jdbcType=VARCHAR},

UPDATE_DATE=#{updateDate,jdbcType=DATE},

SALE_COUNT=#{saleCount},

WHERE

ID = #{id,jdbcType=INTEGER}

SELECT

FROM

XQ_SCHOOL_INFO

WHERE

STATUS = 1

AND AREA_ID = #{areaId}

SELECT

FROM

XQ_SCHOOL_INFO

WHERE

STATUS = 1

ORDER BY ID DESC

SELECT

i.*,

yc.NAME as 'CITY_NAME',

ya.NAME as 'AREA_NAME'

FROM

XQ_SCHOOL_INFO i

LEFT JOIN YW_CITY_SETTING yc ON i.CITY_CODE = yc.CODE

LEFT JOIN YW_CITY_SETTING ya ON i.AREA_CODE = ya.CODE

WHERE

i.STATUS = 1

AND i.CITY_CODE=#{city}

AND i.AREA_CODE=#{area}

AND i.ID=#{schoolId}

AND i.NAME LIKE concat('%',#{schoolName},'%')

AND i.AREA_ID=#{schoolDistrictId}

AND i.TYPE=#{schoolType}

AND (i.NAME LIKE CONCAT('%',#{key},'%') OR i.ALIAS LIKE CONCAT('%', #{key}, '%'))

/*priceType == 1:起售价 2:房源售均价*/

AND SALE_PRICE >= #{salePriceStart}

AND SALE_PRICE <= #{salePriceEnd}

AND UNIT_PRICE >= #{salePriceStart}

AND UNIT_PRICE <= #{salePriceEnd}

AND SCHOOL_DEGREE = 100

AND SCHOOL_DEGREE < 100

ORDER BY ID DESC

SELECT

FROM

XQ_SCHOOL_INFO

WHERE

STATUS = 1

AND NAME = #{name}

AND CITY_CODE=#{city}

AND AREA_CODE=#{area}

AND TYPE = #{type}

SELECT

XSI.*,CYCS.NAME AS 'CITY_NAME',AYCS.NAME AS 'AREA_NAME'

FROM

XQ_SCHOOL_INFO XSI

LEFT JOIN YW_CITY_SETTING CYCS ON XSI.CITY_CODE = CYCS.CODE

LEFT JOIN YW_CITY_SETTING AYCS ON XSI.AREA_CODE = AYCS. CODE

WHERE

1=1

AND XSI.AREA_CODE=#{areaId}

AND (XSI.NAME like CONCAT(#{key},'%' ) or XSI.NAME_SPELL like CONCAT(#{key},'%' ))

AND

XSI.STATUS=1

limit #{pageSize}

SELECT DISTINCT AREA_ID FROM XQ_SCHOOL_INFO WHERE NAME LIKE CONCAT('%',#{schoolName},'%')

SELECT

FROM

XQ_SCHOOL_INFO

WHERE

STATUS = 1

AND ID IN

#{item}

AND AREA_ID = #{areaId}

Java框架tk_TKmybatis的框架介绍和原理分析及Mybatis新特性相关推荐

  1. AbstractQueuedSynchronizer的介绍和原理分析

    简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过 ...

  2. java进阶Kafka集群实战之原理分析及优化教程全在这里

    我不去想是否能够成功 既然选择了Java 便只顾风雨兼程 我不去想能否征服Kafka集群 既然钟情于Java 就勇敢地追随千锋 我不去想Kafka集群有多么晦涩难懂 既然目标是远方 留给世界的只能是努 ...

  3. Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析

    转载自  Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析 Java中的阻塞队列接口BlockingQueue继承自Queue接口. Block ...

  4. 【Java学习笔记之二十八】深入了解Java8新特性

    前言: Java 8 已经发布很久了,很多报道表明java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java ...

  5. Java 数据交换格式反射机制SpringIOC原理分析

    数据交换格式&反射机制&SpringIOC原理分析 什么是数据交换格式? 数据交换格式使用场景 JSON简单使用 什么是JSON? JSON格式的分类 常用JSON解析框架 使用fas ...

  6. Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析

    1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...

  7. Java常见bean mapper的性能及原理分析

    来源:http://r6d.cn/VxXn 背景 在分层的代码架构中,层与层之间的对象避免不了要做很多转换.赋值等操作,这些操作重复且繁琐,于是乎催生出很多工具来优雅,高效地完成这个操作,有BeanU ...

  8. Java程序员进阶——Spring依赖注入原理分析

    Spring依赖注入原理分析 下面谈谈Spring是如何实现反转模式IOC或依赖注入模式DI: 平时,我们需要生成一个对象,使用new语法,如一个类为A public class A{public v ...

  9. arthas 运维工具介绍与原理分析

    目录 arthas是什么?他能帮我们做什么? arthas使用举例 arthas 实现这些功能的原理分析 arthas是什么?他能帮我们做什么? Arthas 是一款线上监控诊断产品,通过全局视角实时 ...

最新文章

  1. angular ng-show ng-hide的兼容性问题
  2. 将tensorflow训练好的模型移植到Android (MNIST手写数字识别)
  3. Codeforces 892E Envy
  4. mac下用xattr命令来删除文件的扩展属性
  5. 你第1个100万怎么赚的?
  6. Drupal 修复远程代码执行漏洞
  7. 嵌入式linux蓝牙通讯,开发板蓝牙通信问题,有这方面经验的请进
  8. 几种常用 css3 选择器解释
  9. python命令行安装包
  10. 最新版 INSPINIA IN+ - WebApp Admin Theme v2.7.1,包含asp.net MVC5示例代码,做管理系统最佳的选择。...
  11. 原码一位乘法和补码一位乘法
  12. 简单SNIFFER 应用驱动安装及使用
  13. 微信小程序 体验版开启调试模式
  14. css渐变背景色与切角
  15. 手把手教你用Python采集腾讯招聘数据
  16. LOJ 3090 「BJOI2019」勘破神机——斯特林数+递推式求通项+扩域
  17. 灵活的Vue组件——原来这么简单
  18. 异步AsyncTask,怎样停止AsyncTask和Thread
  19. Web技术-1 Web前端总结
  20. python函数定义的语法形式_Python 函数(一) 基本语法

热门文章

  1. 视频直播系统源码,实例源码系列-设置系统时间
  2. knockoutjs介绍(译文)
  3. 一次windows server 2003系统修复过程
  4. 为您的 Vue.js 应用程序选择最佳电子商务平台
  5. 加密解密五种算法的实现
  6. 洛谷P3150 pb的游戏(1)
  7. 【总结】56个JavaScript 实用工具函数助你提升开发效率!
  8. Unity 安装 Device Simulator
  9. 長井志江:AI模拟并协助自闭症患者,探究人类认知与意识本质|42问AI与机器人未来...
  10. 神经网络适用于什么问题,神经网络的优点和缺点