前言

Unix domain socket 又叫 IPC(inter-process communication 进程间通信)socket,用于实现同一主机上的进程间通信。
socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
Unix 套接字:Unix 套接字、 UNIX 域套接字、 Unix 域协议族AF_UNIX、POSIX 本地进程间通信套接字、POSIX 本地 IPC 套接字、、、、、、——所有这些术语或多或少指的是同一个概念——主机内部协议和寻址该方案或多或少类似于 Internet 上计算机之间的套接字通信。通常,但并非总是如此,Unix 套接字由文件系统上的路径名引用。PF_UNIXPF_LOCALAF_FILEPF_FILE
Unix 套接字可用于多种平台(包括 macOS、Windows 和 Linux),它们的工作方式都略有不同。

Unix域套接字有兴趣的同学可以百度查找相关资料,这里不再赘述;

由上可知,unix套接字的通讯效率是高于socket通讯的,在同一台服务器上使用unix domian socket进行进程间的通讯,也能提高我们的通讯效率,例如同一台服务java server与java serverjava server与mysqljava server与postgresqljava server与docker等通讯,可以使用unix domain socket进行数据交互,可以提高执行效率,同时也也避免了服务对外暴露端口,提高的安全性

这篇文章主要实现java通过unix domain socket技术对mysql数据库的应用,主要涉及步骤讲解、代码示例;后续也会提供java基于unix domain socket实现Socketrmipostgresql应用,尤其java通过unix domain socket技术调用postgresql数据库,我们工作中涉及到的应用最多,后续会着重讲解;

注:为了方便大家使用,本文介绍两种unix domain socket连接mysql数据库的方式:java + jdbcspring boot + mybatis

mysql.sock简介

“mysql.sock”是mysql的套接字文件,是mysql的主机和客户机在同一host上的时候,使用unix socket做为通讯协议的载体。在UNIX系列系统下本地连接MySQL可以采用TCP连接UNIX域套接字两种方式;其中UNIX域套接字方式需要一个套接字文件,可用“show variables like ‘socket’\G;”命令来查看本地socket文件位置。

MySQL 中我们常用的有两种连接数据库的方式,分别是:

  1. TCP/IP
mysql -uyouruser -pyourpassword -P3306 -h127.0.0.1
mysql -uyouruser -pyourpassword -P3306 -h192.168.199.198
  1. Socket
mysql -uyouruser -pyourpassword --socket=/tmp/mysql.sock
mysql -uyouruser -pyourpassword -hlocalhost
mysql -uyouruser -pyourpassword

以上三种方式是等价的,默认不填时,默认--host=localhost--socket=/tmp/mysql.sock

登录示例

mysql使用 Unix 域套接字连接:

Connector/J 本身不支持使用 Unix 域套接字连接到 MySQL 服务器。但是,可以使用通过可插入套接字工厂提供功能的第 3 方库。这样的自定义工厂应该实现 Connector/J 的 com.mysql.cj.protocol.SocketFactory 接口或遗留 com.mysql.jdbc.SocketFactory接口。当您为 Unix 套接字使用此类自定义套接字工厂时,请遵循以下要求:
1)MySQL 服务器必须配置系统变量 --socket(对于使用 JDBC API 的本机协议连接)或 --mysqlx-socket(对于使用 X DevAPI 的 X 协议连接),它必须包含 Unix 套接字文件的文件路径。
2)自定义工厂的完全限定类名应该通过连接属性传递给 Connector/J socketFactory。例如,对于 junixsocket 库,设置:

socketFactory=org.newsclub.net.mysql.AFUNIXDatabaseSocketFactory

您可能还需要将其他参数作为连接属性传递给自定义工厂。例如,对于 junixsocket 库,提供具有以下属性的套接字文件的文件路径junixsocket.file

junixsocket.file=path_to_socket_file

3)Fore release 8.0.21 及更早版本:使用 X 协议时,设置连接属性 xdevapi.useAsyncProtocol=false(这是 Connector/J 8.0.12 及更高版本的默认设置)。异步套接字通道不支持 Unix 套接字。当 时xdevapi.useAsyncProtocol=true,该 socketFactory属性将被忽略(连接属性 xdevapi.useAsyncProtocol自 8.0.22 版以来已被弃用)。

注:可以参考MySQL Connector/J 8.0 开发人员指南


代码实现

创建数据库表student

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,`name` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,`sex` char(6) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,`pwd` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,`email` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = DYNAMIC;SET FOREIGN_KEY_CHECKS = 1;

连接socket,创建AFUNIXDatabaseSocketFactoryCJ类:

package com.config;import com.mysql.cj.conf.PropertySet;
import com.mysql.cj.conf.RuntimeProperty;
import com.mysql.cj.protocol.ServerSession;
import com.mysql.cj.protocol.SocketConnection;
import com.mysql.cj.protocol.SocketFactory;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketAddress;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.Socket;public class AFUNIXDatabaseSocketFactoryCJ implements SocketFactory {private AFUNIXSocket rawSocket;private Socket sslSocket;@Overridepublic <T extends Closeable> T connect(String s, int i, PropertySet propertySet, int i1) throws IOException {RuntimeProperty<String> prop = propertySet.getStringProperty("junixsocket.file");String sock;if (prop != null && !prop.isExplicitlySet()) {sock = prop.getStringValue();} else {sock = "/var/lib/mysql/mysql.sock";}final File socketFile = new File(sock);this.rawSocket = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(socketFile));this.sslSocket = rawSocket;return (T) rawSocket;}@Overridepublic <T extends Closeable> T performTlsHandshake(SocketConnection socketConnection, ServerSession serverSession) throws IOException {return null;}
}

建立数据库Connection连接:

package com.sk.jdbc;import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;public class MysqlDemo {//建立connection连接public static Connection getConn() throws Exception{Driver driver = new com.mysql.cj.jdbc.Driver();String url = "jdbc:mysql://localhost/test";//将用户名和密码封装在Properties中Properties info = new Properties();info.setProperty("socketFactory","com.config.AFUNIXDatabaseSocketFactoryCJ");info.setProperty("user","root");info.setProperty("password","%Dsh0406");info.setProperty("junixsocket.file","/var/lib/mysql/mysql.sock");info.setProperty("sslMode","DISABLED");Connection conn = driver.connect(url,info);System.out.println(conn);return conn;}//通过conn操作数据库,主要用于jdbc实现public static List<String> run() throws Exception{Connection conn = getConn();Statement stmt = conn.createStatement();String sql = "select * from student";ResultSet rs = stmt.executeQuery(sql);//处理结果集List<String> res = new ArrayList<>();while(rs.next()) {String str = rs.getString("name");res.add(str);}rs.close();System.out.println("结果集关闭成功!");stmt.close();System.out.println("语句通道关闭成功!");conn.close();System.out.println("关闭连接成功!");//遍历输出if(res!=null){for(String out:res) {System.out.println(out);}}return res;}
}

jdbc实现对数据库调用,结合上一步的run()

package com.controller;import com.bean.Student;
import com.mapper.StudentMapper;
import com.sk.jdbc.MysqlDemo;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;@Log4j2
@RestController
public class TestAction {@Resourceprivate StudentMapper studentMapper;/*** 验证jdbc调用* @return*/@GetMapping("/test/local")private Object get(){try {return MysqlDemo.run();} catch (Exception e) {e.printStackTrace();}return null;}
}

jdbc调用执行结果:
日志信息

接口调用:

集合springboot+mybatis使用
创建mapper

package com.mapper;import com.bean.Student;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;import java.util.List;
import java.util.Map;@Mapper
@Repository
public interface StudentMapper {@Select("select * from student")List<Student> selectAll();@Select("select * from student where id = #{id}")Student selectById(@Param("id") int id);@Select("select * from student where name = #{name}")Map<String, Object> selectByName1(@Param("name") String name);@Select("select * from student where name = #{name}")Student selectByName2(@Param("name") String name);@Select("select * from student where name = #{name} and pwd = #{pwd}")Student selectByNameAndPwd(String name, String pwd);@Delete("delete from student where id = #{id}")boolean deleteById(int id);@Insert("insert into student values (null,#{name},#{sex},#{pwd},#{email})")boolean insertUser(String name, String sex, String pwd, String email);@Update("update student set name =  #{name} where id = #{id}")boolean updateById(String name, int id);}

重写DataSourceMyDataSource.java

package com.config;import com.sk.jdbc.MysqlDemo;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;public class MyDataSource implements DataSource {@Overridepublic Connection getConnection() {try {return MysqlDemo.getConn();} catch (Exception e) {e.printStackTrace();}return null;}@Overridepublic Connection getConnection(String username, String password) {try {return MysqlDemo.getConn();} catch (Exception e) {e.printStackTrace();}return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}
}

手动初始化数据库连接DruidConfig.java

package com.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;@Configuration
public class DruidConfig {@Beanpublic DataSource druid(){return new MyDataSource();}}

创建验证接口

package com.controller;import com.bean.Student;
import com.mapper.StudentMapper;
import com.sk.jdbc.MysqlDemo;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;@Log4j2
@RestController
public class TestAction {@Resourceprivate StudentMapper studentMapper;/*** 验证mybatis* @return*/@GetMapping("/test")private Object get2(){List<Student> studentList = studentMapper.selectAll();log.info(studentList);return studentList;}
}

执行结果:

参考资料:
https://github.com/kohlschutter/junixsocket
https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-unix-socket.html
https://mp.weixin.qq.com/s/h3jOYAD05QfHSRXLnQtPYw

=有下午茶,必开会

【技术应用】java基于UNIX域套接字(unix domain socket)连接mysql数据库相关推荐

  1. 基于JAVA基于web的老年公寓管理计算机毕业设计源码+系统+mysql数据库+lw文档+部署

    基于JAVA基于web的老年公寓管理计算机毕业设计源码+系统+mysql数据库+lw文档+部署 基于JAVA基于web的老年公寓管理计算机毕业设计源码+系统+mysql数据库+lw文档+部署 本源码技 ...

  2. 阿里云自动java和mysql数据库_阿里云服务器之基于Linux系统部署上线JavaWeb项目和连接MySQL数据库(从购买云服务器到发布JavaWeb项目全套详细流程)...

    阿里云服务器之基于Linux系统部署上线JavaWeb项目和连接MySQL数据库(从购买云服务器到发布JavaWeb项目全套详细流程) (仅此纪念人生第一篇学习博客) 前阵子接了一个小小的JavaWe ...

  3. Java新手入门200例124之用JDBC连接Mysql数据库

    文章目录 作者简介 引言 导航 热门专栏推荐 一.创建web项目 二.加入Mysql驱动 三.编写查询代码 四.测试查询代码 五.编写插入代码 六.编写修改代码 七.编写删除代码 小结 导航 热门专栏 ...

  4. unix 域套接字实现进程间通信

             目录 1.认识域套接字 2.unix域套接字相关API及地址结构介绍 (1) 创建unix域套接字 (2) 填充地址结构 sockaddr_un 3.unix域套接字实现进程间通信( ...

  5. 域服务器广播消息,广播,组播和UNIX域套接字

    1.广播 1.特点 一对多 仅能使用UDP 2.概念 发送方只有一个接收方则称单播 如果同时发给局域网中的所有主机,成为广播 只有用户数据包(使用UDP协议)套接字才能广播 广播地址 1.以192.1 ...

  6. linux 套接字 文件 路径,linux – 识别unix域套接字连接的另一端

    我正在试图找出一个持有unix域套接字另一端的进程.在某些strace输出中,我已经确定了一个给定的文件描述符,这个文件描述符涉及到我目前正在调试的问题,我想知道哪一个进程在另一端.由于存在与该套接字 ...

  7. UNIX域套接字编程和socketpair 函数

    一.UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络soc ...

  8. Beats:将 Unix 域套接字中的数据索引到 Elastic Stack

    这篇博文将解释什么是 UNIX 域套接字,以及如何将发送到 UNIX 域套接字的索引编入 Elastic Stack - 以及为此存在哪些不同的用例. UNIX 域套接字 - 简短的历史 如果你想让进 ...

  9. 【socket】 unix域套接字(socketpair )通信|socketpair和pipe的区别|进程间通信-Unix domain socket

    目录 unix域套接字(socketpair )通信|socketpair和pipe的区别 socketpair机制 描述 原理 socketpair和pipe的区别 进程间通信-Unix domai ...

最新文章

  1. 在windows中安装python
  2. hdu 2516 FIB博弈模型
  3. DataX在数据迁移中的应用
  4. u3d 总是背向相机_纪念光学科学家“肖特”的相机
  5. php用mssql还是用pdo,php使用pdo连接mssql server数据库实例
  6. TSQLDBServerHttpApi使用工作线程池
  7. 简单好用的Adapter---ArrayAdapter
  8. Swagger自动接口文档生成框架————springboot整合swagger总结
  9. TokenInsight:BTC网络活跃度保持历史高位,人气居高不下
  10. win10配置清华源——快速安装anaconda、TensorFlow和pytorch
  11. PIE SDK 坐标系创建、定义、对比
  12. Web 网页开发的一点心得
  13. 微信8.0.0中的[烟花]\[炸弹]原来还可以这样玩(JAVA脚本)程序员的快乐,很简单,快来看!!!
  14. Win10虚拟机性能优化
  15. CMAQ-5.2安装及测试数据运行
  16. 8.3 初步理解 Texture Alpha
  17. 【元宵节】中国人民大学与加拿大女王大学金融硕士项目与你的那份“缘”
  18. mysql中图片的属性名是啥_数据库属性名
  19. 电脑无法连接wifi得解决方法
  20. uniapp实现微信小程序websocket+背景音频语音播报

热门文章

  1. divergence
  2. 2022华东杯B题中证红利指数投资问题思路讲解
  3. L2-010 排座位(C语言并查集)
  4. iphonex 测试电池软件,iPhone X电池测试:续航给力 充电不能忍!
  5. 鼠标滑轮,上下滑动变成了音量控制键?
  6. 【Bzoj4326】运输计划
  7. aws 认证_如何在家工作时获得任何AWS认证
  8. redis 不同数据结构使用场景
  9. 物联网课程学习目标_【笨办法学物联网】之一: 物联网工程专业四年里应该学习哪些实用技能傍身?...
  10. DHCP中继原理解析