数据分片产生的背景,可以查看https://shardingsphere.apache.org/document/current/cn/features/sharding/,包括了垂直拆分和水平拆分的概念.还有这个框架的目标是什么,都写得很清楚

Sharding-JDBC与MyCat:

  • 解决分库分表的中间件.
  • 但是定位不同,Sharding-JDBC定位是轻量级Java框架,以jar包的方式提供服务,未使用中间件,使用代码连接库.MyCat相当于代理,MyCat相当于数据库,直接访问MyCat就可以,不需要关系库和表,MyCat自动处理,但是需要维护MyCat,性能会有损耗.

Sharding-JDBC(1.x):

github地址: https://github.com/apache/incubator-shardingsphere/releases
官网: https://shardingsphere.incubator.apache.org/
文档: https://shardingsphere.apache.org/document/current/en/overview/

功能:

  • 分库分表:

    • SQL解析功能完善,支持聚合,分组,排序,LIMIT,OR等查询,并且支持级联表以及笛卡尔积的表查询
    • 支持内、外连接查询
    • 分片策略灵活,可支持=,BETWEEN,IN等多维度分片,也可支持多分片键共用,以及自定义分片策略
    • 基于Hint的强制分库分表路由
  • 读写分离:
    • 一主多从的读写分离配置,可配合分库分表使用
    • 基于Hint的强制主库路由
  • 分布式事务:
    • 最大努力送达型事务
    • TCC型事务(TBD)
  • 兼容性: 兼容各大ORM框架
    • 可适用于任何基于java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC
    • 可基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid等
    • 理论上可支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL
  • 灵活多样配置:
    • Java
    • Spring命名空间
    • YAML
    • Inline表达式
  • 分布式生成全局主键: 统一的分布式基于时间序列的ID生成器

使用Sharding-JDBC进行读写分离实战

在数据库的操作中,写操作是非常耗时的,而最常用的是读操作,读写分离的目的是避免数据库的写操作影响读操作的效率.最重要的目的还是减少数据库的压力,提高性能.

这只是模仿读写分析实战,流程是创建两个数据库,配置两个数据源,一个是主表,一个是从表,写修改删除在主表,查询是在从表.

  1. 创建数据库的语句:
// 主表
CREATE DATABASE `ds_0` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
// 从表
CREATE DATABASE `ds_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';// 两个库中都创建表
CREATE TABLE `user`(id bigint(64) not null auto_increment,city varchar(20) not null,name varchar(20) not null,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;// 插入ds_0
insert into user values(1001,'上海','尹吉欢');
// 插入ds_1
insert into user values(1002,'北京','张三');
  1. 创建项目,引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version>
</dependency>
<dependency><groupId>com.dangdang</groupId><artifactId>sharding-jdbc-config-spring</artifactId><version>1.5.4.1</version>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
  1. 配置文件的编写(使用xml的方式来实现):
// 创建sharding.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:rdb="http://www.dangdang.com/schema/ddframe/rdb" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.dangdang.com/schema/ddframe/rdb http://www.dangdang.com/schema/ddframe/rdb/rdb.xsd "><!-- 主数据 --><bean id="ds_0" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" primary="true"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/ds_0?serverTimezone=UTC&amp;characterEncoding=utf-8&amp;useInformationSchema=true" /><property name="username" value="root" /><property name="password" value="nrblwbb7" /></bean><!-- 从数据 --><bean id="ds_1" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/ds_1?serverTimezone=UTC&amp;ccharacterEncoding=utf-8" /><property name="username" value="root" /><property name="password" value="nrblwbb7" /></bean><!-- 读写分离数据源 --><rdb:master-slave-data-source id="dataSource" master-data-source-ref="ds_0" slave-data-sources-ref="ds_1"/><!-- 增强版JdbcTemplate --><!--<bean id="cxytiandiJdbcTemplate" class="com.cxytiandi.jdbc.CxytiandiJdbcTemplate"><property name="dataSource" ref="dataSource"/><constructor-arg><value>com.cxytiandi.shardingjdbc.po</value></constructor-arg></bean>--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean>
</beans>
  1. 编写model,service,controller
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User implements Serializable {private static final long serialVersionUID = -1205226416664488559L;private Long id;private String city = "";private String name = "";}public interface UserService {void save(User user);Object findAll();
}@Service
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void save(User user) {jdbcTemplate.execute("INSERT INTO USER(city,name) values ('"+user.getCity()+"','"+user.getName()+"')");log.info("进行插入操作, {} : ","插入成功");}@Overridepublic Object findAll() {Integer integer = jdbcTemplate.queryForObject("SELECT COUNT(id) FROM USER", Integer.class);log.info("从表的数据的条数是 {} 条",integer);return integer;}
}@RestController
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/save")public String save(){userService.save(User.builder().id(1001L).city("运城").name("王智").build());return "OK";}@GetMapping("/list")public Object list(){return userService.findAll();}
}
  1. 启动类:
@SpringBootApplication
@Slf4j
@ImportResource(locations = {"classpath:sharding.xml"})
public class ShardingJdbcDemoApplication {public static void main(String[] args) {SpringApplication.run(ShardingJdbcDemoApplication.class, args);}}

运行进行访问,先进行save操作,到数据库查看可以看到两条数据,之后进行list操作,返回结果1,说明插入(写)操作在主表,查询在从表.

强制路由

以为在主表和从表之间同步是需要时间的,所以有的时候在写完之后就要立即进行读操作,所以这个时候就需要强制路由,让从主表中读取.

ShardingSphere使用ThreadLocal管理分片键值。可以通过编程的方式向HintManager中添加分片条件,该分片条件仅在当前线程内生效。

 HintManager.getInstance().setMasterRouteOnly();

在查询前使用这句可以指定从主库中进行读取数据.

分片算法

参考: https://blog.csdn.net/gjx8010/article/details/72542207#1-%E5%88%86%E7%89%87%E6%9E%9A%E4%B8%BE

  1. 分片枚举: 通过在配置文件中配置可能的枚举id,自己配置分片。 这种规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国的省份区县固定的,这类业务使用这一规则。
  2. 范围约定: 此分片适用于提前规划好分片字段某个范围属于哪个分片. 这个接触过,就是比如说id在1~10000的在一张表,10001~20000在另一张表.
  3. 取模: 比如说两张表,奇数存一张表,偶数存一张表.
  4. 按日期进行分片: 比如说一天一张表,或者一个月一张表(这个一般是看业务需求).

还有很多,不过我觉得我比较喜欢的就这几个,Hash的也很常用,只是我没有用过.真正用过的就是范围约定了.

分库分表

分库分表就是表面上的意思,将一个库分为多个库,讲一个表分为多个表.

单库分表

在前一个项目上进行修改

  1. 首先创建数据库ds_03,在数据库中创建4张表
CREATE DATABASE `ds_2` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';CREATE TABLE `user_0` (`id` bigint(64) NOT NULL AUTO_INCREMENT,`city` varchar(20) NOT NULL,`name` varchar(20) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;依次创建user_1,user_2,user_3
  1. 重新创建xml文件sharding-table.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:rdb="http://www.dangdang.com/schema/ddframe/rdb" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.dangdang.com/schema/ddframe/rdb http://www.dangdang.com/schema/ddframe/rdb/rdb.xsd "><!-- inline表达式报错,就是下面user_${id.longValue() % 4}} --><context:property-placeholder  ignore-unresolvable="true"/> <!-- 主数据 --><bean id="ds_2" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" primary="true"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/ds_2?serverTimezone=UTC&amp;characterEncoding=utf-8" /><property name="username" value="root" /><property name="password" value="nrblwbb7" /></bean><!-- algorithm-class="com.cxytiandi.shardingjdbc.UserSingleKeyTableShardingAlgorithm" --><!-- user_0,user_1,user_2,user_3 --><!-- 根据用户id来进行分表,使用inline表达式 --><rdb:strategy id="userTableStrategy" sharding-columns="id" algorithm-expression="user_${id.longValue() % 4}"/><!--使用自定义表达式--><!--<rdb:strategy id="userTableStrategy" sharding-columns="id" algorithm-class="com.sharding.shardingjdbcdemo.UserSingleKeyTableShardingAlgorithm"/>--><rdb:data-source id="dataSource"><rdb:sharding-rule data-sources="ds_2"><rdb:table-rules><rdb:table-rule logic-table="user" actual-tables="user_${0..3}" table-strategy="userTableStrategy"/></rdb:table-rules><rdb:default-database-strategy sharding-columns="none" algorithm-class="com.dangdang.ddframe.rdb.sharding.api.strategy.database.NoneDatabaseShardingAlgorithm"/></rdb:sharding-rule></rdb:data-source><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean></beans>

上面在使用分表的时候使用的是inline表达式.还有一种自定义表达式,上面是注释掉的,使用的是类来进行分表,但是我测试过程一直是类型转换异常,Integer转不成Long,这个错误清除,不知道发生在哪,因为着急,就不仔细研究了,下面把自定义表达式的类贴出来,有兴趣的可以试试.

public class UserSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {@Overridepublic String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {for (String each : availableTargetNames) {if (each.endsWith(shardingValue.getValue() % 4 + "")) {return each;}}throw new IllegalArgumentException();}@Overridepublic Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());for (Long value : shardingValue.getValues()) {for (String tableName : availableTargetNames) {if (tableName.endsWith(value % 4 + "")) {result.add(tableName);}}}return result;}@Overridepublic Collection<String> doBetweenSharding(Collection<String> availableTargetNames,ShardingValue<Long> shardingValue) {Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());Range<Long> range = (Range<Long>) shardingValue.getValueRange();for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {for (String each : availableTargetNames) {if (each.endsWith(i % 4 + "")) {result.add(each);}}}return result;}
}
  1. 编写controller
@GetMapping("/saves")
public String saves(){for (Long i = 1L; i <= 100L; i++) {User user = User.builder().name("王智" + i).city("运城").build();user.setId(i);userService.save(user);log.info("插入的数据为 {} " ,user);}return "ok";
}

这下就可以测试了,在开始的时候写的sql不是指明了表是User,我就非常疑惑这个是怎么替换为user_0~4的,这个是sharding0-jdbc自动帮我们做的,我觉得应该类似拦截器的实现吧,也没有细究,只知道有这么回事.

分库分表

前面说了单库分表,那分库分表呢?一样的实现.

  1. 创建数据库和表
CREATE DATABASE `sharding_0` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE DATABASE `sharding_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';// 在每一个数据库中都创建两张表
CREATE TABLE `user_0`(id bigint(64) not null,city varchar(20) not null,name varchar(20) not null,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `user_1`(id bigint(64) not null,city varchar(20) not null,name varchar(20) not null,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. 创建sharding-db-table.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:rdb="http://www.dangdang.com/schema/ddframe/rdb" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.dangdang.com/schema/ddframe/rdb http://www.dangdang.com/schema/ddframe/rdb/rdb.xsd "><!-- inline表达式报错 --><context:property-placeholder  ignore-unresolvable="true"/> <!-- 主数据 --><bean id="ds_0" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" primary="true"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/sharding_0?serverTimezone=UTC&amp;characterEncoding=utf-8" /><property name="username" value="root" /><property name="password" value="nrblwbb7" /></bean><bean id="ds_1" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/sharding_1?serverTimezone=UTC&amp;characterEncoding=utf-8" /><property name="username" value="root" /><property name="password" value="nrblwbb7" /></bean><!--数据库按照城市划分,一个城市一个数据库--><rdb:strategy id="databaseShardingStrategyHouseLouDong" sharding-columns="city" algorithm-class="com.sharding.shardingjdbcdemo.SingleKeyDbShardingAlgorithm"/><!--数据库的表按照id划分,奇数id存1,偶数id存0--><rdb:strategy id="tableShardingStrategyHouseLouDong" sharding-columns="id" algorithm-expression="user_${id.longValue() % 2}" /><rdb:data-source id="dataSource"><rdb:sharding-rule data-sources="ds_0, ds_1"><rdb:table-rules><rdb:table-rule logic-table="user" actual-tables="user_${0..1}" database-strategy="databaseShardingStrategyHouseLouDong" table-strategy="tableShardingStrategyHouseLouDong"><rdb:generate-key-column column-name="id"/></rdb:table-rule></rdb:table-rules></rdb:sharding-rule></rdb:data-source><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean>
</beans>
  1. 添加数据库的分库策略
public class SingleKeyDbShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<String>  {private static Map<String, List<String>> shardingMap = new ConcurrentHashMap<>();static {shardingMap.put("ds_0", Arrays.asList("山西"));shardingMap.put("ds_1", Arrays.asList("陕西"));}@Overridepublic String doEqualSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {for (String each : availableTargetNames) {if (shardingMap.get(each).contains(shardingValue.getValue())) {return each;}}return "ds_0";}@Overridepublic Collection<String> doInSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());for (String each : availableTargetNames) {if (shardingMap.get(each).contains(shardingValue.getValue())) {result.add(each);} else {result.add("ds_0");}}return result;}@Overridepublic Collection<String> doBetweenSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());for (String each : availableTargetNames) {if (shardingMap.get(each).contains(shardingValue.getValue())) {result.add(each);} else {result.add("ds_0");}}return result;}}
  1. 修改controller中的saves方法,进行测试:
 @GetMapping("/saves")
public String saves(){for (Long i = 1L; i <= 100L; i++) {User user = User.builder().name("王智" + i).city("山西").build();user.setId(i);userService.save(user);log.info("插入的数据为 {} " ,user);}for (Long i = 1L; i <= 100L; i++) {User user = User.builder().name("王智" + i).city("陕西").build();user.setId(i);userService.save(user);log.info("插入的数据为 {} " ,user);}return "ok";
}

这个是基于jdbc做的分库分表,对于spring,springboot下有不同的方法,参考 https://shardingsphere.apache.org/document/current/cn/manual/sharding-jdbc/usage/sharding/

分布式主键的使用

为了保证插入的主键不重复,所以使用分布式主键,其实在前面的xml中已经添加了实现<rdb:generate-key-column column-name="id"/>,接下来只要修改saves方法和save方法的实现就可以,也就是不给id赋值,并且插入的时候不给id字段,不过我在实践过程中发现生成的id全是偶数,不知道是不是偶然,如果不是,那么就需要重新找算法或者重新写分配策略了.

基本就先这样了,后面有需要的进一步研究,还是看官方文档比较好 https://shardingsphere.apache.org/document/current/cn/features/sharding/

上面的例子都亲身实践过,有问题可以私聊我,我是看了http://cxytiandi.com/course/15 这个视频课还有官方文档来写的,视频里用的是作者是进一步封装了jdbcTemplate,笔者用的是jdbcTemplate.

转载于:https://www.cnblogs.com/wadmwz/p/10481413.html

分库分表中间件sharding-jdbc的使用相关推荐

  1. 【分布式mysql分库分表中间件sharding】

    分布式mysql分库分表中间件,sharding领域的一站式解决方案.具备丰富.灵活的路由算法支持,能够方便DBA实现库的水平扩容和降低数据迁移成本.shark采用应用集成架构,放弃通用性,只为换取更 ...

  2. 一文快速入门分库分表中间件 Sharding-JDBC (必修课)

    书接上文 <一文快速入门分库分表(必修课)>,这篇拖了好长的时间,本来计划在一周前就该写完的,结果家庭内部突然人事调整,领导层进行权利交接,随之宣布我正式当爹,紧接着家庭地位滑落至第三名, ...

  3. 一文快速入门分库分表中间件 Sharding-JDBC

    一.Sharding-JDBC 简介 Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名 ...

  4. 【Sharding-JDBC系列二】一文快速入门分库分表中间件 Sharding-JDBC (必修课)

    作为Sharding-JDBC 分库分表实战系列的开篇文章,我们在前文中回顾了一下分库分表的基础知识,对分库分表的拆分方式有了一定的了解,下边我们介绍一下 Sharding-JDBC框架和快速的搭建一 ...

  5. 【数据库与事务系列】分库分表中间件

    前面讲了利用mybatis插件进行多数据源切换和分表的方案,但是对业务侵入性较强,当然给予mybatis-plus的对业务侵入性还好,但是支持的策略有限.场景有限. 所以业界诞生了很多分库分表中间件来 ...

  6. 关系型数据库分库分表中间件之选型

    写在前面 本文主要介绍关系型数据库分库分表的中间件,主要包含中间件介绍.选项及其对比.虽然市面上很多分库分表中间件,但是大多数都是不友好或者社区活跃度不高的项目,当然还是有很多淘汰的中间件.目前,在实 ...

  7. 数据库分库分表中间件对比(很全)

    数据库(分库分表)中间件对比 分区:对业务透明,分区只不过把存放数据的文件分成了许多小块,例如mysql中的一张表对应三个文件.MYD,MYI,frm. 根据一定的规则把数据文件(MYD)和索引文件( ...

  8. 分库分表中间件Sharding-JDBC

    数据库分库分表从互联网时代开启至今,一直是热门话题.在NoSQL横行的今天,关系型数据库凭借其稳定.查询灵活.兼容等特性,仍被大多数公司作为首选数据库.因此,合理采用分库分表技术应对海量数据和高并发对 ...

  9. Mycat - 数据库分库分表中间件,国内最活跃的、性能最好的开源数据库中间件

    转载自 Mycat - 数据库分库分表中间件,国内最活跃的.性能最好的开源数据库中间件 Mycat是什么 Mycat - 数据库分库分表中间件,国内最活跃的.性能最好的开源数据库中间件! 一个彻底开源 ...

  10. 自己动手写一个分库分表中间件(三)数据源路由实现

    相关文章: 自己动手写一个分库分表中间件(一)思考 自己动手写一个分库分表中间件(二)数据源定义和分片代理层设计 排查项目中读写分离失效原因 小议 Java 内省机制 注:本文内容暂不涉及事务相关的问 ...

最新文章

  1. 【Flutter】Dart 数据类型 Map 类型 ( 创建 Map 集合 | 初始化 Map 集合 | 遍历 Map 集合 )
  2. ListView使用技巧-更新中
  3. 进程和线程的基本概念
  4. composer 完整路径才能访问_Win7系统IIS,无法访问ASP,提示错误 '80004005'
  5. MFC通过对话框窗口句柄获得对话框对象指针
  6. Android中级之网络数据解析一之Json解析
  7. 在线教育如何应对流量洪峰?阿里云专家:上云+云数据库是最佳路径
  8. MongoDB C#:如何将包含DateTime的JSON反序列化为正确的BsonDocument DateTime值
  9. 机器学习方向企业面试题(二)
  10. 三国演义词云的python代码_词云制作没那么难,Python 10 行代码就实现了!
  11. HDU2002 计算球体积【入门】
  12. 音视频开发-websocket教程
  13. oracle 索引个数限制,oracle索引详解
  14. C语言 正序输出数字
  15. Error on rename ofXXXXXX (errno: 152)
  16. 数据库sql简单的优化方案
  17. 突然断电对oracle的影响吗,当ORACLE突然断电,重新启动过程发生了哪些事?
  18. 泊松图像编辑(Poisson image editing)
  19. 伪静态、静态、动态url
  20. Spark:利用tac+cellid基站定位

热门文章

  1. JDK的问题:用C启动虚拟机跟java运行结果有差异
  2. 为什么给他们讲WP的技术秘密
  3. SVN的代码回滚,并不如预期的那样好
  4. 安卓GLSurfaceView使用简单范例
  5. FFMpeg新旧接口之间的一些对应关系
  6. 全网首发:WINDOWS某些文件夹,提供管理员权限后也无法删除,正确解决办法
  7. 客气话要靠谱。比如公司业务一直没开展,却说学到了太多东西,那学的难道是怎样把公司搞死?
  8. Visitor(访问者)
  9. mysql 高级查询总结_MySQL高级查询
  10. mac卸载python3.8_如何使用Homebrew在Mac上默认设置Python3.8?