java代码实现mysql分表操作(用户行为记录)

设置项目气动执行次方法(每天检查一次表记录)

public class DayInterval implements ServletContextListener{
	private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	public static void showDayTime() {
			Timer dTimer = new Timer();
			dTimer.schedule(new TimerTask() {
			@Override
			public void run() {
			  System.out.println("每日任务执行:"+simpleDateFormat.format(new Date()));
			  LogTableCreate logTableCreate = new LogTableCreate();
			  Thread thread=new Thread(logTableCreate);
			  thread.start();
			}
			}, 1000 , 24* 60* 60 * 1000);//24* 60* 60 * 1000(第一次一秒后执行,以后每次一天后执行)
	}
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
//		showDayTime();
	}
	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		showDayTime();
	}
}

LogTableCreate 用来做表分表是否已经创建,如现在是9月在启动时检查是否存在当月表记录,不存在则创建存在则不创建,另外检查是否存在10月份表记录,不存在则创建(提前创建一个也空表,以此类推)。

拷贝代码修改createsql(建表sql),URL (数据库地址),USER (数据库连接用户),PASSWORD(数据库连接密码)

public class LogTableCreate extends TimerTask {
	private static final Log log = LogFactory.getLog(LogTableCreate.class);
	public static final String TBASENAME="tb_log";
		private String createsql = " (\r\n" +
				" `ID` varchar(64) NOT NULL COMMENT '主键id',\r\n" +
				" `userid` varchar(255) DEFAULT NULL COMMENT '用户id',\r\n" +
				" `username` varchar(255) DEFAULT NULL COMMENT '用户姓名',\r\n" +
				" `useridcard` varchar(255) DEFAULT NULL COMMENT '用户身份证号码',\r\n" +
				" `realname` varchar(64) DEFAULT NULL COMMENT '真实姓名',\r\n" +
				" `logintime` varchar(255) DEFAULT NULL COMMENT '登录时间',\r\n" +
				" `exittime` varchar(64) DEFAULT NULL COMMENT '退出时间',\r\n" +
				" `ippath` varchar(255) DEFAULT NULL COMMENT 'ip地址',\r\n" +
				" `macpath` varchar(255) DEFAULT NULL COMMENT 'mac地址',\r\n" +
				" `usercreatedtime` varchar(255) DEFAULT NULL COMMENT '用户创建时间',\r\n" +
				" `userbusidaddress` varchar(255) DEFAULT NULL COMMENT '用户钱包地址',\r\n" +
				" `member` int(11) DEFAULT NULL COMMENT '是否是会员',\r\n" +
				" `membertype` int(11) DEFAULT NULL COMMENT '会员类型',\r\n" +
				" `spare1` varchar(255) DEFAULT NULL,\r\n" +
				" `spare2` varchar(255) DEFAULT NULL,\r\n" +
				" `spare3` varchar(255) DEFAULT NULL,\r\n" +
				" PRIMARY KEY (`ID`)\r\n" +
				")";
 private SimpleDateFormat sdyyyy = new SimpleDateFormat("yyyy");
 private SimpleDateFormat sdmm = new SimpleDateFormat("MM");
 private static final String URL = "";
 private static final String USER = "";
 private static final String PASSWORD = "";
 //得到表名
 public static String gettable() {
 	Date date = new Date();
 	LogTableCreate logTableCreate=new LogTableCreate();
		String yyyy = logTableCreate.sdyyyy.format(date);
		String mm = logTableCreate.sdmm.format(date);
		String nmm = logTableCreate.getNextMM(mm);
		return TBASENAME+yyyy+mm;
 }

	//得到下一个月
	private String getNextMM(String mm){
		String nmm = "";
		int imm = Integer.parseInt(mm);
		if(imm>=12){
			nmm = "01";
		}else{
			imm++;
			if(imm>9)
				nmm = ""+imm;
			else
				nmm = "0"+imm;
		}
		return nmm;
	}
	@Override
	public void run() {
		Date date = new Date();
		String yyyy = sdyyyy.format(date);
		String mm = sdmm.format(date);
		String nmm = getNextMM(mm);

		String nyyyy = "";
		if("01".equals(nmm)){
			nyyyy = ""+(Integer.parseInt(yyyy)+1);
		}else{
			nyyyy = yyyy;
		}

		log.info("日志表检查及创建:"+yyyy+" - "+mm+" | "+nyyyy+"-"+nmm);
		String temp = TBASENAME+yyyy+mm; //日志表名称
		boolean has = false;

		try{
			has = hasTable(temp);
		}catch(Exception e){
			log.error("当前操作日志表是否存在判断时发生错误:"+e.getMessage());
			return;
		}
		if(!has){
			try{
				createTable(temp);
			}catch(Exception e){
				log.error("当前操作日志表创建时发生错误:"+e.getMessage());
				return;
			}
		}
		temp = TBASENAME+nyyyy+nmm;
		has = false;
		try{
			has = hasTable(temp);
		}catch(Exception e){
			log.error("待用日志表是否存在判断时发生错误:"+e.getMessage());
			return;
		}
		if(!has){
			try{
				createTable(temp);
			}catch(Exception e){
				log.error("待用日志表创建时发生错误:"+e.getMessage());
				return;
			}
		}

		log.info("日志表检查及创建结束");
	}

	public boolean hasTable(String table) throws Exception{
		Class.forName("com.mysql.jdbc.Driver");
  //2. 获得数据库连接
 Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
		boolean state = false;
		DatabaseMetaData meta = conn.getMetaData();
		ResultSet set;
		set = meta.getTables(null, null, table.toLowerCase(), null);
		while (set.next()) {
			state = true;
			break;
		}
		Statement stmt = null;
		try{
			stmt = conn.createStatement();
		}catch(Exception e){
			log.error("检查日志表是否存在时发生错误:"+e.getMessage());
			throw e;
		}finally{
			if(stmt!=null)
				try {
					stmt.close();
				} catch (Exception e) {
					//e.printStackTrace();
				}
		}
		conn.close();
		return state;
	}
	public void createTable(String table)throws Exception{
		try{
		Class.forName("com.mysql.jdbc.Driver");
	  //2. 获得数据库连接
	 Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
		String sql = "create table "+table+createsql;
		Statement stmt = null;
		stmt = conn.createStatement();
		stmt.execute(sql);
		}catch(Exception e){
			log.error("初始化日志表时发生错误:"+e.getMessage());
			throw e;
		}
	}
}

补充:java水平分表_Java开发分库分表需要解决的问题及mycat是怎样实现分库分表的

引言

从字面上简单理解,就是把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上。

数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;

另外,由于无法进行分布式式部署,而一台服务器的资源(CPU、磁盘、内存、IO等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。

分库分表的必要性

首先我们来了解一下为什么要做分库分表。在我们的业务(web应用)中,关系型数据库本身比较容易成为系统性能瓶颈,单机存储容量、连接数、处理能力等都很有限,数据库本身的“有状态性”导致了它并不像Web和应用服务器那么容易扩展。那么在我们的业务中,是否真的有必要进行分库分表,就可以从上面几个条件来考虑。

单机储存容量。您的数据量是否在单机储存中碰到瓶颈。比如饿了么一天产生的用户行为数据就有24T,那么在传统的单机储存中肯定是不够的。

连接数、处理能力。在我们的用户量达到一定程度时,特定时间的并发量又成了一个大问题,在一个高并发的网站中秒级数十万的并发量都是很正常的。在普通的单机数据库中秒级千次的操作问题都很大。

所以在我们进行分库分表之前我们最好考虑一下,我们的数据量是不是够大,并发量是不是够大。如果您的回答是肯定的,那我们就开始做吧。

事务问题

解决事务问题目前有两种可行的方案:分布式事务和通过应用程序与数据库共同控制实现事务下面对两套方案进行一个简单的对比。

方案一:使用分布式事务

优点:交由数据库管理,简单有效

缺点:性能代价高,特别是shard越来越多时

方案二:由应用程序和数据库共同控制

原理:将一个跨多个数据库的分布式事务分拆成多个仅处 于单个数据库上面的小事务,并通过应用程序来总控 各个小事务。

优点:性能上有优势

缺点:需要应用程序在事务控制上做灵活设计。如果使用 了spring的事务管理,改动起来会面临一定的困难。

分库分表的实施策略。

分库分表有垂直切分和水平切分两种。

3.1 何谓垂直切分,即将表按照功能模块、关系密切程度划分出来,部署到不同的库上。

例如,我们会建立定义数据库workDB、商品数据库payDB、用户数据库userDB、日志数据库logDB等,分别用于存储项目数据定义表、商品定义表、用户数据表、日志数据表等。

3.2 何谓水平切分,当一个表中的数据量过大时,我们可以把该表的数据按照某种规则,例如userID散列,进行划分,然后存储到多个结构相同的表,和不同的库上。

例如,我们的userDB中的用户数据表中,每一个表的数据量都很大,就可以把userDB切分为结构相同的多个userDB:part0DB、part1DB等,再将userDB上的用户数据表userTable,切分为很多userTable:userTable0、userTable1等,然后将这些表按照一定的规则存储到多个userDB上。

3.3 应该使用哪一种方式来实施数据库分库分表,这要看数据库中数据量的瓶颈所在,并综合项目的业务类型进行考虑。

如果数据库是因为表太多而造成海量数据,并且项目的各项业务逻辑划分清晰、低耦合,那么规则简单明了、容易实施的垂直切分必是首选。

而如果数据库中的表并不多,但单表的数据量很大、或数据热度很高,这种情况之下就应该选择水平切分,水平切分比垂直切分要复杂一些,它将原本逻辑上属于一体的数据进行了物理分割,除了在分割时要对分割的粒度做好评估,考虑数据平均和负载平均,后期也将对项目人员及应用程序产生额外的数据管理负担。

在现实项目中,往往是这两种情况兼而有之,这就需要做出权衡,甚至既需要垂直切分,又需要水平切分。我们的游戏项目便综合使用了垂直与水平切分,我们首先对数据库进行垂直切分,然后,再针对一部分表,通常是用户数据表,进行水平切分。

mycat是怎样实现分库分表的?mycat里面通过定义路由规则来实现分片表(路由规则里面会定义分片字段,以及分片算法)。分片算法有多种,你所说的hash是其中一种,还有取模、按范围分片等等。在mycat里面,会对所有传递的sql语句做路由处理(路由处理的依据就是表是否分片,如果分片,那么需要依据分片字段和对应的分片算法来判断sql应该传递到哪一个、或者哪几个、又或者全部节点去执行)

总结

以上就是我对Java开发分库分表需要解决的问题及mycat是怎样实现分库分表的 问题及其优化总结,如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • MySQL分表和分区的具体实现方法

    垂直分表 垂直分表就是一个包含有很多列的表拆分成多个表,比如表A包含20个字段,现在拆分成表A1和A2,两个表各十个字段(具体如何拆根据业务来选择). 优势:在高并发的情境下,可以减少表锁和行锁的次数. 劣势:在数据记录非常大的情况下,读写速度还是会遇到瓶颈. 水平分表 假如某个网站,它的数据库的某个表已经达到了上亿条记录,那么此时如果通过select去查询,在没有索引的情况下,他的查询会非常慢,那么就可以通过hash算法将这个表分成10个子表(此时每个表的 的数据量只有1000万条了). 同时

  • MySQL分区表的正确使用方法

    MySQL分区表概述 我们经常遇到一张表里面保存了上亿甚至过十亿的记录,这些表里面保存了大量的历史记录. 对于这些历史数据的清理是一个非常头疼事情,由于所有的数据都一个普通的表里.所以只能是启用一个或多个带where条件的delete语句去删除(一般where条件是时间). 这对数据库的造成了很大压力.即使我们把这些删除了,但底层的数据文件并没有变小.面对这类问题,最有效的方法就是在使用分区表.最常见的分区方法就是按照时间进行分区. 分区一个最大的优点就是可以非常高效的进行历史数据的清理. 1.

  • MySQL 分表优化试验代码

    这里的分表逻辑是根据t_group表的user_name组的个数来分的.因为这种情况单独user_name字段上的索引就属于烂索引.起不了啥名明显的效果. 1.试验PROCEDURE.DELIMITER $$DROP PROCEDURE `t_girl`.`sp_split_table`$$CREATE  PROCEDURE `t_girl`.`sp_split_table`()BEGIN  declare done int default 0;  declare v_user_name var

  • java代码实现mysql分表操作(用户行为记录)

    设置项目气动执行次方法(每天检查一次表记录) public class DayInterval implements ServletContextListener{ private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void showDayTime() { Timer dTimer = new Timer(); dTime

  • Java使用Sharding-JDBC分库分表进行操作

    目录 主从库搭建 Compose File Master 配置 Slave 配置 主从配置 创建分库分表 Order 1 库 Order 2 库 User 库 Sharding-JDBC 引入 Sharding-JDBC 配置 可选配置 数据源配置 主从复制配置 数据节点配置 Demo 程序 Sharding-JDBC 是无侵入式的 MySQL 分库分表操作工具,所有库表设置仅需要在配置文件中配置即可,无须修改任何代码. 本文写了一个 Demo,使用的是 SpringBoot 框架,通过 Doc

  • Java中ShardingSphere分库分表实战

    目录 一. 项目需求 二. 简介sharding-sphere 三. 项目实战 四. 测试 一. 项目需求 我们做项目的时候,数据量比较大,单表千万级别的,需要分库分表,于是在网上搜索这方面的开源框架,最常见的就是mycat,sharding-sphere,最终我选择后者,用它来做分库分表比较容易上手. 二. 简介sharding-sphere 官网地址: https://shardingsphere.apache.org/ ShardingSphere是一套开源的分布式数据库中间件解决方案组成

  • MySql分表、分库、分片和分区知识点介绍

    一.前言 数据库的数据量达到一定程度之后,为避免带来系统性能上的瓶颈.需要进行数据的处理,采用的手段是分区.分片.分库.分表. 二.分片(类似分库) 分片是把数据库横向扩展(Scale Out)到多个物理节点上的一种有效的方式,其主要目的是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题.Shard这个词的意思是"碎片".如果将一个数据库当作一块大玻璃,将这块玻璃打碎,那么每一小块都称为数据库的碎片(DatabaseShard).将整个数据库打碎的过程就叫做分片,可以

  • MySql分表、分库、分片和分区知识深入详解

    一.前言 数据库的数据量达到一定程度之后,为避免带来系统性能上的瓶颈.需要进行数据的处理,采用的手段是分区.分片.分库.分表. 二.分片(类似分库) 分片是把数据库横向扩展(Scale Out)到多个物理节点上的一种有效的方式,其主要目的是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题.Shard这个词的意思是"碎片".如果将一个数据库当作一块大玻璃,将这块玻璃打碎,那么每一小块都称为数据库的碎片(DatabaseShard).将整个数据库打碎的过程就叫做分片,可以

  • mysql分表之后如何平滑上线详解

    目录 分表的目的 举个栗子 分表策略 已经上线的运行中的表怎么办? 步骤1 上线双写 步骤2 全量同步 步骤3 查询新表数据 总结 分表的目的 项目开发中,我们的数据库数据越来越大,随之而来的是单个表中数据太多.以至于查询数据变慢,而且由于表的锁机制导致应用操作也受到严重影响,出现了数据库性能瓶颈. 当出现这种情况时,我们可以考虑分表,即将单个数据库表进行拆分,拆分成多个数据表,然后用户访问的时候,根据一定的算法,让用户访问不同的表,这样数据分散到多个数据表中,减少了单个数据表的访问压力.提升了

  • mysql分表和分区的区别浅析

    一.什么是mysql分表和分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表 什么是分区,分区呢就是把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上 二.mysql分表和分区有什么区别呢 1.实现方式上 a)mysql的分表是真正的分表,一张表分成很多表后,每一个小表都是完正的一张表,都对应三个文件,一个.MYD数据文件,.MYI索引文件,.frm表结构文件. 复制代码 代码如下: [root@BlackGhost test]# ls |grep use

  • MySQL 分表分库怎么进行数据切分

    关系型数据库本身比较容易成为系统瓶颈,单机存储容量.连接数.处理能力都有限.当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库.优化索引,做很多操作时性能仍下降严重.此时就要考虑对其进行切分了,切分的目的就在于减少数据库的负担,缩短查询时间. 数据库分布式核心内容无非就是数据切分(Sharding)以及切分后对数据的定位.整合.数据切分就是将数据分散存储到多个数据库中,使得单一数据库中的数据量变小,通过扩充主机的数量缓解单一数据库的性能问题,从而达到提升数据库操作性能的目

  • mysql分表程序改动方法

    mysql分表 程序如何改动 1.实现分表的原理如下 2.做mysql集群利用mysql cluster ,mysql proxy,mysql replication,drdb的命令如下 3.出现大数据量并且访问频繁的表-->将其分为若干个表.方法代码如下 4.创建表的方法代码 5.实现拆成二张表user1和user2,每张表25W条数据的方法代码.插入的数据方法代码 6.实现更新的方法代码

  • PHP框架Laravel中使用UUID实现数据分表操作示例

    本文实例讲述了PHP框架Laravel中使用UUID实现数据分表操作.分享给大家供大家参考,具体如下: UUID UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的. 说的简单点,它就是通过一个规则(如:业务标识号+年月日+当日自增数字格式化)生成的一个具有唯一性的辨识资讯.用于关联我们的一些额数据和资讯. 实例 之前在做一个项目的时候用到这个东西,现在我就用Laravel框架写一个简单的demo 前端form表单 <!DOCTYPE html> <html&g

随机推荐