Spring整合Sharding-JDBC分库分表详情

Spring整合Sharding-JDBC分库分表详情Spring整合Sharding-JDBC分库分表详情一、概述最初线上系统的业务量不是很大,业务数据量并不大,比如说单库的数据量在百万级别以下(事实上千万级别以下都还能支撑),那么MySQL的单库即可完成任何增/删/改/查的业务操作。随着业务的发展,单个DB中保存的数据量(用户、订单、计费明细和权限规则等数据)呈现指数级增长,那么各种业务处理操作都会面临单DB的IO读写瓶颈带来的性能问题。S…

大家好,又见面了,我是你们的朋友全栈君。

Spring整合Sharding-JDBC分库分表详情

一、概述

最初线上系统的业务量不是很大,业务数据量并不大,比如说单库的数据量在百万级别以下(事实上千万级别以下都还能支撑),那么MySQL的单库即可完成任何增/删/改/查的业务操作。随着业务的发展,单个DB中保存的数据量(用户、订单、计费明细和权限规则等数据)呈现指数级增长,那么各种业务处理操作都会面临单DB的IO读写瓶颈带来的性能问题。

Sharding-JDBC分库分表就是其中一个解决方法,目前用的还挺广泛的,虽然还是有蛮多问题,但是对于公司的普通应用已经足够了。

其实,如果仅仅是分表,Mybatis等中间件就可以帮我们实现简单分表功能,不需要使用Sharding-JDBC,但是Sharding-JDBC可以支持分库,而且支持分库的本地事务(弱事务):

Sharding-JDBC本地事务官方说明:

  • 完全支持非跨库事务,例如:仅分表,或分库但是路由的结果在单库中。

  • 完全支持因逻辑异常导致的跨库事务。例如:同一事务中,跨两个库更新。更新完毕后,抛出空指针,则两个库的内容都能回滚。

  • 不支持因网络、硬件异常导致的跨库事务。例如:同一事务中,跨两个库更新,更新完毕后、未提交之前,第一个库宕机,则只有第二个库数据提交。

首发地址:

  品茗IT-同步发布

品茗IT提供在线支持:

  一键快速构建Spring项目工具

  一键快速构建SpringBoot项目工具

  一键快速构建SpringCloud项目工具

  一站式Springboot项目生成

  Mysql一键生成Mybatis注解Mapper

  Mysql一键生成SpringDataRest项目

如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

二、环境配置

本文假设你已经引入Spring必备的一切了,已经是个Spring项目了,如果不会搭建,可以打开这篇文章看一看《Spring和Spring Mvc 5整合详解》

本篇使用spring-data-jpa做数据库访问,并整合Sharding-JDBC;Mybatis整合Sharding-JDBC相对简单,会在Springboot专题中进行Mybatis与Sharding-JDBC的整合。

2.1 maven依赖

使用Spring-data-jpa需要引入spring-data-jpa,因为是非Springboot项目,我们不能通过starter引入,需要引入spring-data-jpa、javax.transaction-api、hibernate-core。

亲测!Sharding-JDBC使用的mysql-connector-java不能为6.0版本,6.0的所有版本都不能用,换成5.0版本最为稳妥。

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>cn.pomit</groupId>
		<artifactId>SpringWork</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>SpringDataJpa</artifactId>
	<packaging>jar</packaging>
	<name>SpringDataJpa</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>2.0.10.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>javax.transaction-api</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>5.2.17.Final</version>
			<scope>compile</scope>
			<exclusions>
				<exclusion>
					<artifactId>jboss-transaction-api_1.2_spec</artifactId>
					<groupId>org.jboss.spec.javax.transaction</groupId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>
	<build>
		<finalName>SpringDataJpa</finalName>
	</build>
</project>

父模块可以在https://www.pomit.cn/spring/SpringWork/pom.xml获取。

2.2 Spring配置

配置文件分为两部分,一部分是数据源的配置,数据源的配置包含sharding-jdbc的配置,因为sharding-jdbc生成了统一的数据源;包含一部分是jpa的配置。

2.2.1 Shardingjdbc配置

spring-shardingjdbc.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sharding="http://shardingsphere.apache.org/schema/shardingsphere/sharding" xmlns:master-slave="http://shardingsphere.apache.org/schema/shardingsphere/masterslave" 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.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://shardingsphere.apache.org/schema/shardingsphere/sharding http://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsd http://shardingsphere.apache.org/schema/shardingsphere/masterslave http://shardingsphere.apache.org/schema/shardingsphere/masterslave/master-slave.xsd">
    <context:annotation-config />
	<context:component-scan base-package="cn.pomit.springwork.sharding.jdbc">
	</context:component-scan>

	<bean id="annotationPropertyConfigurerJpaLock" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="order" value="1" />
		<property name="ignoreUnresolvablePlaceholders" value="true" />
		<property name="locations">
			<list>
				<value>classpath:db.properties</value>
			</list>
		</property>
	</bean>
	    
    <bean id="ds_master" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.dirverClass}"></property>
		<property name="url" value="${db.url}" />
		<property name="username" value="${db.username}" />
		<property name="password" value="${db.password}" />

		<property name="initialSize" value="1" />
		<property name="minIdle" value="1" />
		<property name="maxTotal" value="20" />

		<property name="validationQuery" value="SELECT 1" />
		<property name="testWhileIdle" value="true" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
    </bean>


    <bean id="ds_slave" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.slave.dirverClass}"></property>
		<property name="url" value="${db.slave.url}" />
		<property name="username" value="${db.slave.username}" />
		<property name="password" value="${db.slave.password}" />

		<property name="initialSize" value="1" />
		<property name="minIdle" value="1" />
		<property name="maxTotal" value="20" />

		<property name="validationQuery" value="SELECT 1" />
		<property name="testWhileIdle" value="true" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
    </bean>
    
    <!-- 4.0.0-RC1 版本 负载均衡策略配置方式 -->
    <bean id="randomStrategy" class="org.apache.shardingsphere.core.strategy.masterslave.RandomMasterSlaveLoadBalanceAlgorithm" />
    
    <!-- 4.0.0-RC2 之后版本 负载均衡策略配置方式 -->
<!-- <master-slave:load-balance-algorithm id="randomStrategy" type="RANDOM" /> -->
    
    <sharding:inline-strategy id="chatTableStrategy" sharding-column="live_id" algorithm-expression="t_chat_info_$->{live_id % 10}" />
    
    <sharding:key-generator id="chatKeyGenerator" type="SNOWFLAKE" column="chat_no" />
    
    <sharding:data-source id="shardingDataSource">
        <sharding:sharding-rule data-source-names="ds_master,ds_slave">
            <sharding:master-slave-rules>
                <sharding:master-slave-rule id="ds_ms0" master-data-source-name="ds_master" slave-data-source-names="ds_slave" strategy-ref="randomStrategy" />
            </sharding:master-slave-rules>
            <sharding:table-rules>
                <sharding:table-rule logic-table="t_chat_info" actual-data-nodes="ds_ms0.t_chat_info_$->{0..9}" table-strategy-ref="chatTableStrategy" key-generator-ref="chatKeyGenerator" />
            </sharding:table-rules>
            <sharding:binding-table-rules>
                <sharding:binding-table-rule logic-tables="t_chat_info" />
            </sharding:binding-table-rules>
        </sharding:sharding-rule>
    </sharding:data-source>
    
    <import resource="classpath*:spring-jpa.xml"/>
</beans>

这里:

  • 配置了两个数据源ds_master和ds_slave,属于不同的库

  • 配置了shardingJdbc的主从查询策略,randomStrategy。需要注意的是读操作默认是从库,如果从库只有一个,那就是这个库

  • chatTableStrategy配置了t_chat_info表的分表策略。

  • chatKeyGenerator配置了注解的策略,并没有什么鸟用,主键还是要自己生成的。

  • shardingDataSource,这个是最主要的配置,将不同的数据源整合成统一的数据源。里面的逻辑是:分库(先指明哪是主库,哪是从库,策略是啥);分表(指明了分表的所有表,分表的策略,分表的逻辑表)。

2.2.2 Spring-data-jpa配置

spring-jpa.xml:

需要配置数据源、jdbcTemplate、entityManagerFactory、transactionManager和jpa:repositories。

<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

	<!-- jdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="shardingDataSource"></property>
	</bean>

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="shardingDataSource"></property>
		<property name="packagesToScan" value="cn.pomit.springwork.sharding.jdbc.domain"></property>
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect">
			</property>
			</bean>
		</property>
		<property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
	</bean>
	<jpa:repositories base-package="cn.pomit.springwork.sharding.jdbc.dao" />
	
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	<!-- 使用annotation定义事务 -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
</beans>

这里面,需要注意的是:

  • entityManagerFactory,是实体和数据库选择信息。

  • jpa:repositories,指明Spring-data-jpa的repositories地址。就是我们的数据库交互层。

  • transactionManager,事务处理器。

  • tx:annotation-driven:开启事务注解。

db.properties中存放数据库的地址端口等连接信息。

2.2.3 配置文件

db.properties:

#主库
db.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
db.username=cff
db.password=123456
#db.dirverClass=com.mysql.cj.jdbc.Driver
#sharding-jdbc不支持6.0以上版本,不得不降级。
db.dirverClass=com.mysql.jdbc.Driver

#从库
db.slave.url=jdbc:mysql://127.0.0.1:3306/cff?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
db.slave.username=cff
db.slave.password=123456
db.slave.dirverClass=com.mysql.jdbc.Driver

#雪花算法的机器id
worker.id=1

三、测试项目

上面都配置完成之后,代码的实现上和普通写代码没区别了。

**需要注意的是,增删改都要带上分表字段,查询可以不带分表字段;**分表字段就是上面定义的sharding-column="live_id"中的live_id.

3.1 Dao数据访问层

直接写一个继承JpaRepository的dao即可。。但是需要注意的是,如果有不带分表字段live_id的查询,需要自己写一个映射,比如下面的findByChatNoAndLiveId.

ChatInfoDao :

package cn.pomit.springwork.sharding.jdbc.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import cn.pomit.springwork.sharding.jdbc.domain.ChatInfo;

@Repository
public interface ChatInfoDao extends JpaRepository<ChatInfo, Long> { 
   
	ChatInfo findByChatNoAndLiveId(Long chatNo, Integer liveId);
}

3.2 Service逻辑层

没啥逻辑,就是个调用。

ChatInfoService:

package cn.pomit.springwork.sharding.jdbc.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.pomit.springwork.sharding.jdbc.dao.ChatInfoDao;
import cn.pomit.springwork.sharding.jdbc.domain.ChatInfo;

@Service
public class ChatInfoService { 
   
	@Autowired
	ChatInfoDao tChatInfoDao;
	@Autowired
	SnowflakeIdGenerator snowflakeIdGenerator;

	public void save(ChatInfo tChatInfo) { 
   
		tChatInfo.setChatNo(snowflakeIdGenerator.nextId());
		tChatInfoDao.save(tChatInfo);
	}

	public void delete(ChatInfo tChatInfo) { 
   
		tChatInfoDao.delete(tChatInfo);
	}

	public void update(ChatInfo tChatInfo) { 
   
		tChatInfoDao.save(tChatInfo);
	}

	public List<ChatInfo> findAll() { 
   
		return tChatInfoDao.findAll();
	}

	public ChatInfo findByChatNoAndLiveId(Integer liveId, Long id) { 
   
		return tChatInfoDao.findByChatNoAndLiveId(id, liveId);
	}

	public ChatInfo findById(Long id) { 
   
		return tChatInfoDao.findById(id).orElse(null);
	}
}

3.3 Web请求层

下面的web请求层,涵盖了sharding-jdbc大多数情况下的使用。

ShardingRest :

package cn.pomit.springwork.sharding.jdbc.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.springwork.sharding.jdbc.domain.ChatInfo;
import cn.pomit.springwork.sharding.jdbc.dto.ResultModel;
import cn.pomit.springwork.sharding.jdbc.service.ChatInfoService;

@RestController
@RequestMapping("/sharing")
public class ShardingRest { 
   

	@Autowired
	ChatInfoService chatInfoService;
	
	@RequestMapping(value = "/add", method = { 
    RequestMethod.POST })
	public ResultModel add(@RequestBody ChatInfo chatInfo) { 
   
		chatInfoService.save(chatInfo);
		return ResultModel.ok();
	}
	
	/** * 查询也要携带分表字段,方便查找数据 * @param chatInfo * @return */
	@RequestMapping(value = "/info", method = { 
    RequestMethod.GET })
	public ResultModel info(@RequestParam("liveId") Integer liveId, @RequestParam("chatNo") Long chatNo) { 
   
		return ResultModel.ok(chatInfoService.findByChatNoAndLiveId(liveId,chatNo));
	}
	
	/** * 不带分表字段查询 * @param chatInfo * @return */
	@RequestMapping(value = "/detail", method = { 
    RequestMethod.GET })
	public ResultModel detail(@RequestParam("chatNo") Long chatNo) { 
   
		return ResultModel.ok(chatInfoService.findById(chatNo));
	}
	
	@RequestMapping(value = "/delete", method = { 
    RequestMethod.POST })
	public ResultModel delete(@RequestBody ChatInfo chatInfo) { 
   
		chatInfoService.delete(chatInfo);
		return ResultModel.ok();
	}
	
	@RequestMapping(value = "/update", method = { 
    RequestMethod.POST })
	public ResultModel update(@RequestBody ChatInfo chatInfo) { 
   
		chatInfoService.update(chatInfo);
		return ResultModel.ok();
	}
}

四、雪花算法

SnowflakeIdGenerator :

package cn.pomit.springwork.sharding.jdbc.service;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


/** * SnowFlake 算法修改 * 0 - 0000000000 00 - 0000000000 0000000000 0000000000 000000000 - 0000 - 00000000 * 符号位 -12位年月位(表示yyMM,最大4096,即可用至2040年)-39位时间戳 (可用17年,即可用至2035年)-4位机器ID(最大16,即可部署16个节点)-8位序列号(z最大256) * @author yujinlong * */
@Component
public class SnowflakeIdGenerator { 
   

    // ==============================Fields===========================================
    /** 开始时间截 (2018-01-01) */
    private final long twepoch = 1514736000000L;
    
    /** 时间戳占的位数 */
    public static final long timestampBits = 39L;

    /** 机器id所占的位数 */
    public static final long workerIdBits = 4L;

    /** 支持的最大机器id,结果是15 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

    /** 序列在id中占的位数 */
    public static final long sequenceBits = 8L;
    
    /** 机器ID向左移6位 */
    private final long workerIdShift = sequenceBits;

    /** 时间截向左移12位(4+8) */
    private final long timestampLeftShift = sequenceBits + workerIdBits;
    
    /** 年月标识左移51位(39 + 4 + 8)*/
    private final long yearMonthLeftShift = sequenceBits + workerIdBits + timestampBits;

    /** 生成序列的掩码,这里为255 */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    /** 工作机器ID(0~16) */
    @Value("${worker.id}")
    private long workerId;

    /** 毫秒内序列(0~256) */
    private long sequence = 0L;

    /** 上次生成ID的时间截 */
    private long lastTimestamp = -1L;

    // ==============================Methods==========================================
    @PostConstruct
    public void init(){ 
   
    	System.out.println(workerId);
    	if(this.workerId < 0 || this.workerId > maxWorkerId){ 
   
    		throw new RuntimeException("workerId(" + this.workerId + ") is out of range [0, 15]");
    	}
    }
    
    /** * 获得下一个ID (该方法是线程安全的) * @return SnowflakeId */
    public synchronized long nextId(long yyMM) { 
   
        long timestamp = timeGen();

        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
        if (timestamp < lastTimestamp) { 
   
            throw new RuntimeException(
                    String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        //如果是同一时间生成的,则进行毫秒内序列
        if (lastTimestamp == timestamp) { 
   
            sequence = (sequence + 1) & sequenceMask;
            //毫秒内序列溢出
            if (sequence == 0) { 
   
                //阻塞到下一个毫秒,获得新的时间戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else { 
   
        	//时间戳改变,毫秒内序列重置
            sequence = 0L;
        }

        //上次生成ID的时间截
        lastTimestamp = timestamp;

        //移位并通过或运算拼到一起组成64位的ID
        long preId = (yyMM << yearMonthLeftShift) | ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
        return preId;
    }
    
    /** * 获得不带年月位的id * @return */
    public synchronized long nextId() { 
   
        long timestamp = timeGen();

        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
        if (timestamp < lastTimestamp) { 
   
            throw new RuntimeException(
                    String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        //如果是同一时间生成的,则进行毫秒内序列
        if (lastTimestamp == timestamp) { 
   
            sequence = (sequence + 1) & sequenceMask;
            //毫秒内序列溢出
            if (sequence == 0) { 
   
                //阻塞到下一个毫秒,获得新的时间戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else { 
   
        	//时间戳改变,毫秒内序列重置
            sequence = 0L;
        }

        //上次生成ID的时间截
        lastTimestamp = timestamp;

        //移位并通过或运算拼到一起组成64位的ID
        long preId = ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
        return preId;
    }

    /** * 阻塞到下一个毫秒,直到获得新的时间戳 * @param lastTimestamp 上次生成ID的时间截 * @return 当前时间戳 */
    protected long tilNextMillis(long lastTimestamp) { 
   
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) { 
   
            timestamp = timeGen();
        }
        return timestamp;
    }

    /** * 返回以毫秒为单位的当前时间 * @return 当前时间(毫秒) */
    protected long timeGen() { 
   
        return System.currentTimeMillis();
    }

	public void setWorkerId(long workerId) { 
   
		this.workerId = workerId;
	}
	
}

五、过程中用到的完整实体和Service

ChatInfo:


package cn.pomit.springwork.sharding.jdbc.domain;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "t_chat_info")
public class ChatInfo { 
   
	@Id
	@Column(name = "chat_no")
	private Long chatNo;
	@Column(name = "user_id")
	private Integer userId;
	@Column(name = "live_id")
	private Integer liveId;
	@Column(name = "nick_name")
	private String nickName;
	@Column(name = "create_time")
	private Date createTime;
	@Column(name = "delete_flag")
	private Integer deleteFlag;
	@Column(name = "read_flag")
	private Integer readFlag;

	public void setChatNo(Long chatNo) { 
   
		this.chatNo = chatNo;
	}

	public Long getChatNo() { 
   
		return chatNo;
	}

	public Integer getUserId() { 
   
		return userId;
	}

	public void setUserId(Integer userId) { 
   
		this.userId = userId;
	}

	public Integer getLiveId() { 
   
		return liveId;
	}

	public void setLiveId(Integer liveId) { 
   
		this.liveId = liveId;
	}

	public String getNickName() { 
   
		return nickName;
	}

	public void setNickName(String nickName) { 
   
		this.nickName = nickName;
	}

	public Date getCreateTime() { 
   
		return createTime;
	}

	public void setCreateTime(Date createTime) { 
   
		this.createTime = createTime;
	}

	public Integer getDeleteFlag() { 
   
		return deleteFlag;
	}

	public void setDeleteFlag(Integer deleteFlag) { 
   
		this.deleteFlag = deleteFlag;
	}

	public Integer getReadFlag() { 
   
		return readFlag;
	}

	public void setReadFlag(Integer readFlag) { 
   
		this.readFlag = readFlag;
	}

}

ResultModel:

package cn.pomit.springwork.sharding.jdbc.dto;

public class ResultModel { 
   

	private String errorCode;
	private String message;
	private Object data;

	public ResultModel() { 
   
	}

	public ResultModel(String errorCode) { 
   
		this.errorCode = errorCode;
	}

	public ResultModel(String errorCode, String message) { 
   
		this.errorCode = errorCode;
		this.message = message;
	}

	public ResultModel(String errorCode, String message, Object data) { 
   
		this.errorCode = errorCode;
		this.message = message;
		this.data = data;
	}

	public String getErrorCode() { 
   
		return errorCode;
	}

	public void setErrorCode(String errorCode) { 
   
		this.errorCode = errorCode;
	}

	public String getMessage() { 
   
		return message;
	}

	public void setMessage(String message) { 
   
		this.message = message;
	}

	public Object getData() { 
   
		return data;
	}

	public void setData(Object data) { 
   
		this.data = data;
	}

	public static ResultModel ok() { 
   
		ResultModel resultModel = new ResultModel("0000", "成功");
		return resultModel;
	}

	public static ResultModel ok(Object data) { 
   
		ResultModel resultModel = new ResultModel("0000", "成功");
		resultModel.setData(data);
		return resultModel;
	}

	public static ResultModel error() { 
   
		ResultModel resultModel = new ResultModel("1111", "失败");
		return resultModel;
	}

	public static ResultModel resultModel(String message) { 
   
		ResultModel resultModel = new ResultModel("1111", message);
		return resultModel;
	}
}

六、过程中得到的结论

得出的结论如下:

快速构建项目

Spring组件化构建

SpringBoot组件化构建

SpringCloud服务化构建

喜欢这篇文章么,喜欢就加入我们一起讨论Spring技术吧!
品茗IT交流群

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/130215.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux安装svn服务器_linux安装svn客户端

    linux安装svn服务器_linux安装svn客户端1.https://tortoisesvn.net/downloads.html网站下载2.安装的时候如果出现下图的报错打开这个网站https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=49062,会自动帮你下载下载完成后安装即可3.没有特殊需求则默认安装4.出现这个则安装成功MySQL安装…

    2022年8月18日
    6
  • Latex插入图片却不显示问题小结

    Latex插入图片却不显示问题小结1、首先检查有没有导入宏包\usepackage{graphicx}2、检查图片路径有无问题3、可以尝试将Tex的同名文件删除,重新编译生成4、若是文章分栏\begin{multicols}{2}那是因为multicols环境不能识别figure环境,重新定义一个环境即可\newenvironment{figurehere}{\def\@captype{figure}}{}\makeatother%用于连接公式编号在文中,用figureher

    2022年5月11日
    42
  • dell服务器安装Ubuntu16.04桌面版(系统安装程序找不到磁盘,无法分区)「建议收藏」

    dell服务器安装Ubuntu16.04桌面版(系统安装程序找不到磁盘,无法分区)「建议收藏」前言前段时间笔者所在的公司服务器突然硬盘挂了,”剧情”需要,笔者担当起了运维的角色,自行在新到的硬盘安装系统,搭建服务器环境…p.s.笔者因为工作需要,在服务器上安装了Ubuntu16.04的桌面版。因为有时候确实很需要图形界面的Linux系统。2333本文仅供有系统安装的经验的同学参考…正文这里废话不多说,桌面版的Ubuntu(后面简称桌板)的和服务器版的Ubuntu(后面简称服版)对于普通电脑来说,安装方式都一样,那么对于服务器来说,桌版和服版来说,安装方式略有不同(这里后面会说到),但工具还

    2025年6月13日
    0
  • 服务器对cpu的性能要求比较高_服务器cpu家用缺点

    服务器对cpu的性能要求比较高_服务器cpu家用缺点如今各种大型游戏对我们的电脑性能的要求越来越高,很多用了三四年的老电脑已经带不动最新的3A巨作了,这时候大家就需要考虑更换电脑或者是升级配置了。假如选择升级配置,效果最显著的就要数更换CPU和显卡了,今天编者就来谈谈由于种种原因,性价比很低几款CPU,假如大家想要更换以下的几款CPU可要三思了。首先,编者不推荐买英特尔的第六、七代酷睿处理器,以i57500为例,散片价格在1200元左右,与同为四…

    2022年9月19日
    0
  • k8s 资源管理_k8s扩容命令

    k8s 资源管理_k8s扩容命令k8s管理器介绍yaml资源管理器介绍管理器介绍在Kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理Kubernetes。Kubernetes的本质就是一个集群系统,用户可以在集群中部署各种服务。所谓的部署服务,其实就是在Kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。Kubernetes的最小管理单元是Pod而不是容器,所以只能将容器放在Pod中,而Kubernetes一般也不会直接管理Pod,而是通过Pod控制器来管理Pod的。Pod提供服务之后

    2022年8月11日
    1
  • Navicat 15 for MySQL 注册激活码_通用破解码

    Navicat 15 for MySQL 注册激活码_通用破解码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月17日
    1.1K

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号