mysql数据业务垂直+水平分割+主从复制读写分离

本文主要是介绍mysql数据业务垂直+水平分割+主从复制读写分离,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、拓扑图:

   垂直+水平分割+主从复制+读写分离完整原理图:

仅说明原理,详细拓扑及参数参考本次实验拓扑图

mysql数据业务垂直+水平分割+主从复制读写分离 - tuchengju - tuchengju的博客

   本次试验拓扑图:(上图左侧部分)


mysql数据业务垂直+水平分割+主从复制读写分离 - tuchengju - tuchengju的博客二、实验描述:

   根据业务原型先进行数据库垂直切割,然后用户数据根据user_id取模360进行水平切割,DB1和DB2创建相同的表结构。0-179存储到DB1,179-359存储到DB2上,其他博客、空间的那个放在其它数据库上,本次只做用户数据。DB1、DB2都采用主从读写分离架构,实现数据冗余和性能优化,实现较大用户承载量。

   DB1-master: 10.0.8.18/16        插入记录user_id % 360 <=179
   DB1-slave: 10.0.8.28/16
   DB1-amoeba: 10.0.8.38/16
   DB2-master: 10.0.8.48/16        插入记录user_id % 360 >170
   DB2-slave: 10.0.8.58/16
   DB2-amoeba: 10.0.8.68/16
   split-amoeba: 10.0.8.78/16
  注意:所有机器关闭selinux和iptables

三、实验过程:
1.环境搭建
1.1DB1和DB2的master、slave都安装mysql5.1.50
创建mysql目录并授权
#useradd -s /sbin/nologin -M mysql
#mkdir -p /data/dbdata
#mkdir -p /usr/local/mysql/tmp/ 
#chown -R mysql:mysql /usr/local/services/mysql
#chown -R mysql:mysql /data/dbdata
#chown -R mysql:mysql /usr/local/mysql
编译安装mysql源码包
#tar xvf mysql-5.1.50.tar.gz
#cd mysql-5.1.50
#./configure '--prefix=/usr/local/services/mysql''--localstatedir=/data/dbdata''--with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock' '--with-charset=utf8''--with-extra-charsets=complex' '--with-pthread' '--enable-thread-safe-client''--with-ssl' '--with-client-ldflags=-all-static' '--with-mysqld-ldflags=-all-static''--with-plugins=partition,federated,ndbcluster,innobase,csv,blackhole,myisam,innodb_plugin,heap,archive''--enable-shared' '--enable-assembler'
# make && make install
初始化mysql
#/usr/local/services/mysql/bin/mysql_install_db --user=mysql--basedir=/usr/local/services/mysql --datadir=/data/dbdata
# cp /usr/local/services/mysql/share/mysql/mysql.server /etc/init.d/mysqld
# chmod 755 /etc/init.d/mysqld
# vim /etc/init.d/mysqld 修改mysql启动脚本,设置数据库目录和安装目录
basedir=/usr/local/services/mysql
datadir=/data/dbdata
修改mysql配置文件
#vim /etc/my.cnf
配置文件在附件中给出,直接覆盖/etc/my.cnf

innodb_buffer_pool_size = 8G

根据服务器内存修改,否者起不来


设置环境变量和启动服务
#vim /etc/profile 修改profile文件,将mysql脚本路径添加到环境变量中去
MYSQL=/usr/local/services/mysql/bin
PATH=$PATH:$MYSQL
export PATH
#source /etc/profile 使环境变量设置生效
#/etc/init.d/mysqld start 启动服务
1.2三台amoeba服务器都安装jdk1.7.1_40和amoeba
解压jdk文件
# mkdir /java
# tar -xvf jdk-7u40-linux-x64.tar.gz -C /java
将jdk路径写到环境变量中去
# vim /etc/profile
JAVA_HOME=/java/jdk1.7.0_40
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH
CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$CLASSPATH
export CLASSPATH 
#source /etc/profile
测试是否已经有JAVA环境
# java -version
java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode) 
安装Amoeba
# unzip amoeba-mysql-1.3.1-BETA.zip -d /usr/local/amoeba/
# chmod -R +x /usr/local/amoeba/bin/
安装mysql客户端
#yum install mysql -y
2.配置主从复制读写分离架构
 2.1在两台master上操作:
修改配置文件my.cnf
#vim /etc/my.cnf
首先将bin-log日志打开
log-bin=mysql-bin
其次将server-id设置为1,默认为1
server-id=1
将log-slave-updates给关闭掉,默认为关闭
修改后重启服务
#/etc/init.d/mysqld restart
登陆数据库,创建主从复制读写分离用户并授权
#mysql 
安装好后默认以root账户登录,没有密码,登陆之后用set password=password('密码')修改,也可以用mysqladmin -uroot-p password '密码'修改
>create user 'amoeba'@'%' identified by 'amoeba'; 创建amoeba用户,密码为amoeba
>grant all privileges on *.* to 'amoeba'@'%' identified by 'amoeba'; 给amoeba用户授予整个数据库完整权限针对所有ip开放。
>grant replication slave on *.* to 'amoeba'@'10.0.8.28' identified by'amoeba'; 给slave服务器授予整个数据库复制权限,IP为从服务器IP
>flush privileges; 刷新权限
>show master status \G; 查看master状态,二进制日志文件名和postion值用于slave服务器配置

mysql数据业务垂直+水平分割+主从复制读写分离 - tuchengju - tuchengju的博客
 2.2在两台slave服务器上操作
修改配置文件my.cnf
首先将bin-log日志打开
其次将server-id设置为2
去掉log-slave-updates前的#
修改好后重启服务
#/etc/init.d/mysqld restart
登陆数据库,创建主从复制读写分离用户并授权
#mysql 
安装好后默认以root账户登录,没有密码,登陆之后用set password=password('密码')修改,也可以用mysqladmin -uroot-p password '密码'修改
>create user 'amoeba'@'%' identified by 'amoeba'; 创建amoeba用户,密码为amoeba
>grant all privileges on *.* to 'amoeba'@'%' identified by 'amoeba'; 给amoeba用户授予整个数据库完整权限针对所有ip开放。
>flush privileges; 刷新权限
>stop slave;
>change master tomaster_host='10.0.8.18',master_user='amoeba',master_password='amoeba',master_log_file='mysql-bin.0000005',master_log_pos=4043;
>start slave;
>show slave status\G; 查看slave状态,IO线程和SQL线程状态都为yes则表示主从复制已经开启成功
主从复制测试
在master上创建一个库为amoeba
>create database amoeba;
在slave上会自动生成一个amoeba库
2.3在两台amoeba读写分离调度器上操作
修改amoeba配置文件amoeba.xml,从上至下
#vim /usr/local/amoeba/conf/amoeba.xml
①修改第一部分本机mysql登陆配置:
================================================
       <!-- proxy server绑定的端口 -->
       <property name="port">8066</property>
       <!-- proxy server绑定的IP -->
<property name="ipAddress">10.0.8.38</property> #另一台为10.0.8.68
       <!-- proxy server net IO Read thread size -->
       <property name="readThreadPoolSize">20</property>
       <!-- proxy server client process thread size -->
       <property name="clientSideThreadPoolSize">30</property>
       <!-- mysql server data packet process thread size -->
       <property name="serverSideThreadPoolSize">30</property>
       <!-- socket Send and receive BufferSize(unit:K) -->
       <property name="netBufferSize">128</property>
       <!-- Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). -->
       <property name="tcpNoDelay">true</property>
       <!-- 对外验证的用户名 -->
       <property name="user">root</property>
       <!-- 对外验证的密码 -->
       <property name="password">aixocm</property> #这里的密码可以任意指定,用来进行读写分离登陆
================================================== 
②修改第二部分:amoeba登陆主从服务器配置
================================================== 
   <dbServer name="server1">
       <!-- PoolableObjectFactory实现类 -->
       <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
           <property name="manager">defaultManager</property>
           <!-- 真实mysql数据库端口 -->
           <property name="port">3306</property>
           <!-- 真实mysql数据库IP -->
           <property name="ipAddress">10.0.8.18</property> #另一台amoeba上为10.0.8.48
           <!--这里的test依赖数据库中的test库-->
           <property name="schema">test</property>
           <!-- 用于登陆mysql的用户名 -->
           <property name="user">amoeba</property>
           <!-- 用于登陆mysql的密码 -->
           <property name="password">amoeba</property>
           </factoryConfig>
       <!-- ObjectPool实现类 -->
       <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
       <property name="maxActive">200</property>
       <property name="maxIdle">200</property>
       <property name="minIdle">10</property>
       <propertyname="minEvictableIdleTimeMillis">600000</property>
       <property name="timeBetweenEvictionRunsMillis">600000</property>
       <property name="testOnBorrow">true</property>
       <property name="testWhileIdle">true</property>
       </poolConfig>
   </dbServer> 
   <dbServer name="server2">
       <!-- PoolableObjectFactory实现类 -->
       <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
           <property name="manager">defaultManager</property>
           <!-- 真实mysql数据库端口 -->
           <property name="port">3306</property>
           <!-- 真实mysql数据库IP -->
           <property name="ipAddress">10.0.8.28</property> #另一台amoeba上为10.0.8.58
           <!--这里的test依赖数据库中的test库-->
           <property name="schema">test</property>
           <!-- 用于登陆mysql的用户名 -->
           <property name="user">amoeba</property>
           <!-- 用于登陆mysql的密码 -->
           <property name="password">amoeba</property>
       </factoryConfig>
       <!-- ObjectPool实现类 -->
       <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
           <property name="maxActive">200</property>
           <property name="maxIdle">200</property>
           <property name="minIdle">10</property>
           <propertyname="minEvictableIdleTimeMillis">600000</property>
           <property name="timeBetweenEvictionRunsMillis">600000</property>
           <property name="testOnBorrow">true</property>
           <property name="testWhileIdle">true</property>
       </poolConfig>
   </dbServer>
=====================================================
③修改的第三部分:负载均衡池
=====================================================
<dbServer name="master" virtual="true">
       <poolConfigclass="com.meidusa.amoeba.server.MultipleServerPool">
           <!-- 负载均衡参数 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
           <property name="loadbalance">1</property>
           <!-- 参与该pool负载均衡的poolName列表以逗号分割 -->
           <property name="poolNames">server1</property>
       </poolConfig>
   </dbServer>
<dbServer name="slave" virtual="true">
       <poolConfigclass="com.meidusa.amoeba.server.MultipleServerPool">
           <!-- 负载均衡参数 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
           <property name="loadbalance">1</property>
           <!-- 参与该pool负载均衡的poolName列表以逗号分割 -->
<propertyname="poolNames">server1,server2</property>
       </poolConfig>
   </dbServer>
读主从的比例默认为1:1,可以进行读权重配置,如server1,server2,server2,server2,server2,这样读4次从服务器,
读一次主服务器,只写主服务器。读主从的比例为变为1:4。
======================================================= 
④修改的第四部分: 配置master和slave的读写分离
=======================================================
   <queryRouterclass="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
       <propertyname="ruleConfig">${amoeba.home}/conf/rule.xml</property>
       <propertyname="functionConfig">${amoeba.home}/conf/functionMap.xml</property>
   <propertyname="ruleFunctionConfig">${amoeba.home}/conf/ruleFunctionMap.xml</property>
       <property name="LRUMapSize">1500</property>
       <!-- 配置master和slave读写分离 Begin-->
       <property name="defaultPool">master</property>
       <property name="writePool">master</property>
       <property name="readPool">slave</property>
       <!-- 配置master和slave读写分离 End-->
       <property name="needParse">true</property>
       </queryRouter> 
=======================================================
修改Amoeba启动脚本
# vim /usr/local/amoeba/bin/amoeba
#DEFAULT_OPTS="-server -Xms256m -Xmx256m -Xss128k" 将此行注释掉,增加一下行
DEFAULT_OPTS="-server -Xms256m -Xmx256m -Xss256k" 增加这一行
运行amoeba脚本
#cd /usr/local/amoeba/bin
#nohup bash -x amoeba & 后台运行amoeba并且记录日志到nohup.out
测试读写分离
在两台master上的amoeba库下创建一个amo表
>use amoeba;
>create table amo(
>user_id int not null unique,
>user_name varchar(45),
>user_address varchar(100),
>primary key(user_id)
>)engine=innodb;
在master和slave上分别插入一条不同记录
master端: >insert into amo(user_id,user_name,user_address)values(1,'master','china');
slave端: >insert into amo(user_id,user_name,user_address)values(2,'slave','china');
在amoeba上进行读写测试
select * from amo 会看到先后两次不同的记录
inset into amo(user_id,user_name,user_address) values(3,'amoeba','china'); 会写到master上然后同步到slave上
3.数据库切割
在amoeba切分器上操作
1.修改配置文件amoeba.xml,从上至下
#vim /usr/local/amoeba/conf/amoeba.xml
①修改的第一部分:本机mysql登陆配置
==============================================================
       <!-- proxy server绑定的端口 -->
       <property name="port">8066</property>
       <!-- proxy server绑定的IP -->
       <property name="ipAddress">10.0.8.78</property> 
       <!-- proxy server net IO Read thread size -->
       <property name="readThreadPoolSize">20</property>
       <!-- proxy server client process thread size -->
       <property name="clientSideThreadPoolSize">30</property>
       <!-- mysql server data packet process thread size -->
       <property name="serverSideThreadPoolSize">30</property>
       <!-- socket Send and receive BufferSize(unit:K) -->
       <property name="netBufferSize">128</property>
       <!-- Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). -->
       <property name="tcpNoDelay">true</property>
       <!-- 对外验证的用户名 -->
       <property name="user">root</property>
       <!-- 对外验证的密码 -->
       <property name="password">aixocm</property> #这里的密码可以任意指定,用来进行读写分离登陆最好统一
=============================================================
②修改的第二部分:amoeba读写分离调度器配置
=============================================================
   <dbServer name="server1">
       <!-- PoolableObjectFactory实现类 -->
       <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
           <property name="manager">defaultManager</property>
           <!-- 真实mysql数据库端口 -->
<property name="port">8066</property> #这里要填写amoeba1配置文件第一部分的端口号,因为ip不同,所以不冲突
           <!-- 真实mysql数据库IP -->
           <property name="ipAddress">10.0.8.38</property>
           <!--这里的test依赖数据库中的test库-->
           <property name="schema">test</property>
           <!-- 用于登陆mysql的用户名 -->
           <property name="user">root</property> #这里要填写amoeba1配置文件第一部分配置的用户和密码
           <!-- 用于登陆mysql的密码 -->
           <property name="password">aixocm</property>
       </factoryConfig>
       <!-- ObjectPool实现类 -->
           <poolConfigclass="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
               <property name="maxActive">200</property>
               <property name="maxIdle">200</property>
               <property name="minIdle">10</property>
               <property name="minEvictableIdleTimeMillis">600000</property>
               <propertyname="timeBetweenEvictionRunsMillis">600000</property>
               <property name="testOnBorrow">true</property>
               <property name="testWhileIdle">true</property>
           </poolConfig>
       </dbServer> 
     <dbServer name="server2">
       <!-- PoolableObjectFactory实现类 -->
       <factoryConfigclass="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
       <property name="manager">defaultManager</property>
       <!-- 真实mysql数据库端口 -->
<property name="port">8066</property>
       <!-- 真实mysql数据库IP -->
       <property name="ipAddress">10.0.8.68</property>
       <!--这里的test依赖数据库中的test库-->
       <property name="schema">test</property>
       <!-- 用于登陆mysql的用户名 -->
       <property name="user">amoeba</property>
       <!-- 用于登陆mysql的密码 -->
<property name="password">amoeba</property>
    </factoryConfig>
    <!-- ObjectPool实现类 -->
        <poolConfigclass="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
           <property name="maxActive">200</property>
           <property name="maxIdle">200</property>
           <property name="minIdle">10</property>
           <property name="minEvictableIdleTimeMillis">600000</property>
           <propertyname="timeBetweenEvictionRunsMillis">600000</property>
           <property name="testOnBorrow">true</property>
           <property name="testWhileIdle">true</property>
       </poolConfig>
   </dbServer> 
================================================================
③修改的第三部分:去掉负载均衡池,或者注释掉
================================================================
   <!-- <dbServer name="multipool" virtual="true">
   <poolConfigclass="com.meidusa.amoeba.server.MultipleServerPool">
   <!-- 负载均衡参数 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
   <property name="loadbalance">1</property>
   <!-- 参与该pool负载均衡的poolName列表以逗号分割 -->
   <property name="poolNames">server1</property>
   </poolConfig>
   </dbServer> 
   -->
=================================================================
2.修改切割规则配置文件
#vim /usr/local/amoeba/conf/rule.xml
<tableRule name="amo" schema="amoeba"defaultPools="server1,server2">

name后为表名,schema后为库名
mysql数据业务垂直+水平分割+主从复制读写分离 - tuchengju - tuchengju的博客


如上图user_id % 360 0到179的记录插入DB1-master,user_id % 360 在180到359的记录插入到DB2-master中
3.修改amoeba启动脚本
# vim /usr/local/amoeba/bin/amoeba
#DEFAULT_OPTS="-server -Xms256m -Xmx256m -Xss128k" 将此行注释掉,增加一下行
DEFAULT_OPTS="-server -Xms256m -Xmx256m -Xss256k" 增加这一行
4.启动amoeba
#nohup bash -x /usr/local/amoeba/bin/amoeba &
5.数据切割测试
amoeba切分器端操作
>use amoeba;
主语要采用标准插入语句
>insert into amo(user_id,uesr_name,user_address) values(177,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(178,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(179,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(180,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(181,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(182,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(359,'user','china');
>insert into amo(user_id,uesr_name,user_address) values(360,'user','china');
master、slave端查看效果,看是否切分成功
6.读写分离测试
在两台slave端分别插入一条记录
然后在amoeba切分器上用select语句查看效果,两次运行select语句结果分别是两台slave的记录和两台master的记录


amoeba切分器进行数据切割时,调用amoeba读写分离服务器进行读写分离,所以amoeba切分器中的server1和server2分别指定的是
amoeba1和amoeba2的ip和8066端口,而不是DB1和DB2的IP登录用户也是amoeba1和amoeba2配置文件第一部分配置的用户和密码
真实生产环境下,amoeba切割器可以用软件实现,利用软件进行切割

这篇关于mysql数据业务垂直+水平分割+主从复制读写分离的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/932987

相关文章

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能