分库分表中间件sharding-jdbc的使用
数据分片产生的背景,可以查看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进行读写分离实战
在数据库的操作中,写操作是非常耗时的,而最常用的是读操作,读写分离的目的是避免数据库的写操作影响读操作的效率.最重要的目的还是减少数据库的压力,提高性能.
这只是模仿读写分析实战,流程是创建两个数据库,配置两个数据源,一个是主表,一个是从表,写修改删除在主表,查询是在从表.
- 创建数据库的语句:
// 主表
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,'北京','张三');
- 创建项目,引入依赖
<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>
- 配置文件的编写(使用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.xsd
http://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&characterEncoding=utf-8&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&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>
- 编写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 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void save(User user) {
jdbcTemplate.execute("INSERT INTO USER(city,name) values ('"+user.getCity()+"','"+user.getName()+"')");
log.info("进行插入操作, {} : ","插入成功");
}
@Override
public Object findAll() {
Integer integer = jdbcTemplate.queryForObject("SELECT COUNT(id) FROM USER", Integer.class);
log.info("从表的数据的条数是 {} 条",integer);
return integer;
}
}
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private 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();
}
}
- 启动类:
@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-分片枚举
- 分片枚举: 通过在配置文件中配置可能的枚举id,自己配置分片。 这种规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国的省份区县固定的,这类业务使用这一规则。
- 范围约定: 此分片适用于提前规划好分片字段某个范围属于哪个分片. 这个接触过,就是比如说id在110000的在一张表,1000120000在另一张表.
- 取模: 比如说两张表,奇数存一张表,偶数存一张表.
- 按日期进行分片: 比如说一天一张表,或者一个月一张表(这个一般是看业务需求).
还有很多,不过我觉得我比较喜欢的就这几个,Hash的也很常用,只是我没有用过.真正用过的就是范围约定了.
分库分表
分库分表就是表面上的意思,将一个库分为多个库,讲一个表分为多个表.
单库分表
在前一个项目上进行修改
- 首先创建数据库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
- 重新创建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.xsd
http://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&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> {
@Override
public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
for (String each : availableTargetNames) {
if (each.endsWith(shardingValue.getValue() % 4 + "")) {
return each;
}
}
throw new IllegalArgumentException();
}
@Override
public 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;
}
@Override
public 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;
}
}
- 编写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自动帮我们做的,我觉得应该类似拦截器的实现吧,也没有细究,只知道有这么回事.
分库分表
前面说了单库分表,那分库分表呢?一样的实现.
- 创建数据库和表
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;
- 创建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.xsd
http://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&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&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>
- 添加数据库的分库策略
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("陕西"));
}
@Override
public 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";
}
@Override
public 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;
}
@Override
public 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;
}
}
- 修改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.
分库分表中间件sharding-jdbc的使用的更多相关文章
- 一文快速入门分库分表中间件 Sharding-JDBC (必修课)
书接上文 <一文快速入门分库分表(必修课)>,这篇拖了好长的时间,本来计划在一周前就该写完的,结果家庭内部突然人事调整,领导层进行权利交接,随之宣布我正式当爹,紧接着家庭地位滑落至第三名, ...
- 当当开源sharding-jdbc,轻量级数据库分库分表中间件
近期,当当开源了数据库分库分表中间件sharding-jdbc. Sharding-JDBC是当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架,实现透明化数据 ...
- 解读分库分表中间件Sharding-JDBC
[编者按]数据库分库分表从互联网时代开启至今,一直是热门话题.在NoSQL横行的今天,关系型数据库凭借其稳定.查询灵活.兼容等特性,仍被大多数公司作为首选数据库.因此,合理采用分库分表技术应对海量数据 ...
- 分库分表中间件Sharding-JDBC
数据库分库分表从互联网时代开启至今,一直是热门话题.在NoSQL横行的今天,关系型数据库凭借其稳定.查询灵活.兼容等特性,仍被大多数公司作为首选数据库.因此,合理采用分库分表技术应对海量数据和高并发对 ...
- 支付宝分库分表中间件--zdal简介
中间件, 如果仅仅作为一名用户的话, 主要关注一下如何使用即可, 大多数情况下也就是配置. 下面简单的介绍一下支付宝的分库分表中间件--->zdal在web项目中的配置. 1, 在网上查阅相关资 ...
- Mysql系列五:数据库分库分表中间件mycat的安装和mycat配置详解
一.mycat的安装 环境准备:准备一台虚拟机192.168.152.128 1. 下载mycat cd /softwarewget http:-linux.tar.gz 2. 解压mycat tar ...
- oracle 分库分表(sharding)
以下文章转载博客:http://blog.csdn.net/bluishglc 讲的很深入透彻,转来分享下: 数据库Sharding的基本思想和切分策 http://blog.csdn.net/blu ...
- sharding-jdbc,轻量级数据库分库分表中间件
Sharding-JDBC是当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问.Sharding-JDBC是继dubbox和ela ...
- 数据库分库分表中间件:Mycat;分布式数据库;mysql的分布式事务
官网:http://mycat.io/,里面有电子书籍可以下载:http://www.mycat.io/document/mycat-definitive-guide.pdf 旧版本下载地址:http ...
随机推荐
- 20155202 张旭《网络对抗》Exp2 后门原理与实践
20155202 张旭<网络对抗>Exp2 后门原理与实践 基础问题回答 例举你能想到的一个后门进入到你系统中的可能方式? 捆绑在软件中 注入在可执行文件里 注入在office文件的宏里面 ...
- Luogu P4322 [JSOI2016]最佳团体
JZdalao昨天上课讲的题目,话说JSOI的题目是真的不难,ZJOI的题目真的是虐啊! 题意很简单,抽象一下就是:有一棵树,一次只能选从根到某个节点上的链上的所有点,问从中取出k个节点所得到的总价值 ...
- EEPROM---AT24Cxx应用介绍
结论:1.读写AT24CXX芯片,根据容量有多种方式:一.容量为AT24C01~AT24C16,首先发送设备地址(8位地址),再发送数据地址(8位地址),再发送或者接受数据. 二.AT24C32/AT ...
- 您需要来自XXX的权限才能对此文件夹进行更改
解决办法: cmd命令:del/f/s/q 文件夹
- 自制一个H5图片拖拽、裁剪插件(原生JS)
前言 如今的H5运营活动中,有很多都是让用户拍照或者上传图片,然后对照片加滤镜.加贴纸.评颜值之类的.尤其是一些拍照软件公司的运营活动几乎全部都是这样的. 博主也做过不少,为了省事就封装了一个简单的图 ...
- Asp.Net_序列化、反序列化
.net序列化及反序列化 在我们深入探讨C#序列化和反序列化之前我们先要明白什么是序列化,它又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制.序列化就是把一个对象保存到一个文件或数据库 ...
- Azure SQL Database Active Geo-Replication 简介
对于数据库的维护来说,备份工作可谓是重中之重.MS Azure 当然也提供了很完善的数据库备份功能.但是在动手创建备份计划前请思考一下备份工作的真实目的.当然首先要保证数据的安全,一般来说定时创建数据 ...
- 【URLOS应用开发基础】10分钟制作一个nginx静态网站环境应用
URLOS开发者功能已上线有一段时间了,目前通过部分开发者的使用体验来看,不得不说URLOS在服务器软件开发效率方面确实有着得天独厚的优势,凭借docker容器技术与其良好的应用生态环境,URLOS必 ...
- Windows 7上安装配置TensorFlow-GPU运算环境
Windows 7上安装配置TensorFlow-GPU运算环境 1. 概述 在深度学习实践中,对于简单的模型和相对较小的数据集,我们可以使用CPU完成建模过程.例如在MNIST数据集上进行手写数字识 ...
- 数据库——SQL数据单表查询
数据查询 语句格式 SELECT [ALL|DISTINCT] <目标列表达式> [,<目标列表达式>] … FROM <表或视图名>[,<表或视图名&g ...