MySql Socket 完成数据库的增查Demo

         需求: 利用MySql数据库结合前端技术完成用户的注册(要求不使用Web服务技术),所以 Demo采用Socket技术实现Web通信.

第一部分:数据库创建

数据库采用mysql 5.7.18, 数据库名称为MyUser, 内部有一张表 user.字段有 Id,UserName,Psd,Tel

 

第二部分:数据库连接与Socket通信

创建控制台程序(服务端程序),添加以下类

1 MySqlHelper

 建立MySqlHelper 类,用于实现数据库操作

public class MysqlHelper{//数据库连接字符串 public static string Conn = "Database='Myuser';Data Source='localhost';User Id='root';Password='';charset='utf8'"; //XXX的为修改项public static   void SetConn(string UserName = "root", string Password="", string IP= "localhost",   string Database="Myuser"){Conn = "datasource="   IP   ";username="   UserName   ";password="   Password   ";database="   Database   ";charset=utf8";}/// <summary> /// 给定连接的数据库用假设参数执行一个sql命令(不返回数据集) /// </summary> /// <param name="connectionString">一个有效的连接字符串</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns>执行命令所影响的行数</returns> public static int ExecuteNonQuery(string connectionString, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){MySqlCommand cmd = new MySqlCommand();using (MySqlConnection conn = new MySqlConnection(connectionString)){PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);int val = cmd.ExecuteNonQuery();cmd.Parameters.Clear();return val;}}/// <summary> /// 用现有的数据库连接执行一个sql命令(不返回数据集) /// </summary> /// <param name="connection">一个现有的数据库连接</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns>执行命令所影响的行数</returns> public static int ExecuteNonQuery(MySqlConnection connection, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){MySqlCommand cmd = new MySqlCommand();PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);int val = cmd.ExecuteNonQuery();//cmd.Parameters.Clear();return val;}/// <summary> ///使用现有的SQL事务执行一个sql命令(不返回数据集) /// </summary> /// <remarks> ///举例: /// int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders", new MySqlParameter("@prodid", 24)); /// </remarks> /// <param name="trans">一个现有的事务</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns>执行命令所影响的行数</returns> public static int ExecuteNonQuery(MySqlTransaction trans, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){MySqlCommand cmd = new MySqlCommand();PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, commandParameters);int val = cmd.ExecuteNonQuery();cmd.Parameters.Clear();return val;}/// <summary> /// 用执行的数据库连接执行一个返回数据集的sql命令 /// </summary> /// <remarks> /// 举例: /// MySqlDataReader r = ExecuteReader(connString, CommandType.StoredProcedure, "PublishOrders", new MySqlParameter("@prodid", 24)); /// </remarks> /// <param name="connectionString">一个有效的连接字符串</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns>包含结果的读取器</returns> public static MySqlDataReader ExecuteReader(string connectionString, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){//创建一个MySqlCommand对象 MySqlCommand cmd = new MySqlCommand();//创建一个MySqlConnection对象 MySqlConnection conn = new MySqlConnection(connectionString);//在这里我们用一个try/catch结构执行sql文本命令/存储过程,因为如果这个方法产生一个异常我们要关闭连接,因为没有读取器存在, //因此commandBehaviour.CloseConnection 就不会执行 try{//调用 PrepareCommand 方法,对 MySqlCommand 对象设置参数 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);//调用 MySqlCommand 的 ExecuteReader 方法 MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);//清除参数 cmd.Parameters.Clear();return reader;}catch{//关闭连接,抛出异常 conn.Close();throw;}}/// <summary> /// 返回DataSet /// </summary> /// <param name="connectionString">一个有效的连接字符串</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns></returns> public static DataSet GetDataSet(string connectionString, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){//创建一个MySqlCommand对象 MySqlCommand cmd = new MySqlCommand();//创建一个MySqlConnection对象 MySqlConnection conn = new MySqlConnection(connectionString);//在这里我们用一个try/catch结构执行sql文本命令/存储过程,因为如果这个方法产生一个异常我们要关闭连接,因为没有读取器存在,try{//调用 PrepareCommand 方法,对 MySqlCommand 对象设置参数 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);//调用 MySqlCommand 的 ExecuteReader 方法 MySqlDataAdapter adapter = new MySqlDataAdapter();adapter.SelectCommand = cmd;DataSet ds = new DataSet();adapter.Fill(ds);//清除参数 cmd.Parameters.Clear();conn.Close();return ds;}catch (Exception e){throw e;}}public static DataTable GetDataTable(string connectionString, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){//创建一个MySqlCommand对象 MySqlCommand cmd = new MySqlCommand();//创建一个MySqlConnection对象 MySqlConnection conn = new MySqlConnection(connectionString);//在这里我们用一个try/catch结构执行sql文本命令/存储过程,因为如果这个方法产生一个异常我们要关闭连接,因为没有读取器存在,try{//调用 PrepareCommand 方法,对 MySqlCommand 对象设置参数 PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);//调用 MySqlCommand 的 ExecuteReader 方法 MySqlDataAdapter adapter = new MySqlDataAdapter();adapter.SelectCommand = cmd;DataTable ds = new DataTable();adapter.Fill(ds);//清除参数 cmd.Parameters.Clear();conn.Close();return ds;}catch (Exception e){throw e;}}/// <summary> /// 用指定的数据库连接字符串执行一个命令并返回一个数据集的第一列 /// </summary> /// <remarks> ///例如: /// Object obj = ExecuteScalar(connString, CommandType.StoredProcedure, "PublishOrders", new MySqlParameter("@prodid", 24)); /// </remarks> ///<param name="connectionString">一个有效的连接字符串</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns>用 Convert.To{Type}把类型转换为想要的 </returns> public static object ExecuteScalar(string connectionString, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){MySqlCommand cmd = new MySqlCommand();using (MySqlConnection connection = new MySqlConnection(connectionString)){PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);object val = cmd.ExecuteScalar();cmd.Parameters.Clear();return val;}}/// <summary> /// 用指定的数据库连接执行一个命令并返回一个数据集的第一列 /// </summary> /// <remarks> /// 例如: /// Object obj = ExecuteScalar(connString, CommandType.StoredProcedure, "PublishOrders", new MySqlParameter("@prodid", 24)); /// </remarks> /// <param name="connection">一个存在的数据库连接</param> /// <param name="cmdType">命令类型(存储过程, 文本, 等等)</param> /// <param name="cmdText">存储过程名称或者sql命令语句</param> /// <param name="commandParameters">执行命令所用参数的集合</param> /// <returns>用 Convert.To{Type}把类型转换为想要的 </returns> public static object ExecuteScalar(MySqlConnection connection, CommandType cmdType, string cmdText, params MySqlParameter[] commandParameters){MySqlCommand cmd = new MySqlCommand();PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);object val = cmd.ExecuteScalar();cmd.Parameters.Clear();return val;}/// <summary> /// 准备执行一个命令 /// </summary> /// <param name="cmd">sql命令</param> /// <param name="conn">OleDb连接</param> /// <param name="trans">OleDb事务</param> /// <param name="cmdType">命令类型例如 存储过程或者文本</param> /// <param name="cmdText">命令文本,例如:Select * from Products</param> /// <param name="cmdParms">执行命令的参数</param> private static void PrepareCommand(MySqlCommand cmd, MySqlConnection conn, MySqlTransaction trans, CommandType cmdType, string cmdText, MySqlParameter[] cmdParms){if (conn.State != ConnectionState.Open)conn.Open();cmd.Connection = conn;cmd.CommandText = cmdText;if (trans != null)cmd.Transaction = trans;cmd.CommandType = cmdType;if (cmdParms != null){foreach (MySqlParameter parm in cmdParms)cmd.Parameters.Add(parm);}}}

  

2,User类与UserHelper类

建立用户类User与用户操作类UserHelper

User

public class User{public int Id { get; set; }public string UserName { get; set; }public string Psd { get; set; }public string PhoneNum { get; set; }}

  

UserHelper

public   class UserHelper{/// <summary>/// 获取用户列表/// </summary>/// <param name="cmdText"></param>/// <returns></returns>public static  List<User> GetUsers(){var cmdText = "select * from Users";var data = MysqlHelper.GetDataSet(MysqlHelper.Conn, System.Data.CommandType.Text, cmdText, new MySql.Data.MySqlClient.MySqlParameter());List<User> userList = new List<User>();foreach (DataRow row in data.Tables[0].Rows){User user = new User();user.Id = int.Parse(row[0].ToString());user.UserName=(row[1].ToString());user.Psd=(row[2].ToString());user.PhoneNum=(row[3].ToString());userList.Add(user);}return userList;}/// <summary>/// 根据姓名查找用户/// </summary>/// <param name="name"></param>/// <returns></returns>public static  User GetUserByName(string name){var cmdText = "select * from Users Where UserName=?name";var pars = new MySql.Data.MySqlClient.MySqlParameter("?name", name);var data = MysqlHelper.GetDataSet(MysqlHelper.Conn, System.Data.CommandType.Text, cmdText, pars);User user = new User();if (data.Tables.Count == 0){return null;}if (data.Tables[0].Rows.Count != 1){return null;}foreach (DataRow row in data.Tables[0].Rows){               user.Id = int.Parse(row[0].ToString());user.UserName = (row[1].ToString());user.Psd = (row[2].ToString());user.PhoneNum = (row[3].ToString());;}return user;}/// <summary>/// 添加用户/// </summary>/// <param name="user"></param>/// <returns></returns>public static bool AddUser(User user){var sqlInsert = "insert into Users(UserName,Psd,Tel) values"  "('"   user.UserName   "','"   user.Psd   "','"   user.PhoneNum   "')";           var parms = new MySqlParameter();var data = MysqlHelper.ExecuteNonQuery(MysqlHelper.Conn, System.Data.CommandType.Text, sqlInsert, parms);return data>0;}}

  

3 Socket

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;

利用Socket技术,可以捕捉Http请求,获取数据.构建SocketHelper类,获取前端页面请求.默认Socket 端口为8086

public class SocketHelper{static Socket m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);/// <summary>/// Socket初始化 /// </summary>public static bool  Init(){try{m_socket.Bind(new IPEndPoint(IPAddress.Any, 8086));m_socket.Listen(100);m_socket.BeginAccept(new AsyncCallback(OnAccept), m_socket);Console.WriteLine("开启Socket服务成功!!");Console.Read();return true;}catch (Exception ){Console.WriteLine("开启Socket服务失败!!,请检查网络,端口8086是否被占用!!!");Console.Read();return false;}}public static void Route(string path, Dictionary<string, string> param, Socket response){if (param.Count == 1){try{var userName = param["userName"];var searUser = UserHelper.GetUserByName(userName);if (searUser != null){HomePage(response, "该用户名已经被占用!!");Console.WriteLine("** - **");Console.WriteLine("用户名"   userName   "被占用");Console.WriteLine("");HomePage(response, "no");}else{HomePage(response, "ok");}}catch (Exception e){HomePage(response, e.Message);Console.WriteLine("** - **");Console.WriteLine("发生错误,错误原因为"   e.Message);Console.WriteLine("");}return;}else if (param.Count == 3) {try{User user = new User();user.UserName = param["userName"];user.Psd = param["psd"];user.PhoneNum = param["phoneNum"];var isSuccess = UserHelper.AddUser(user);if (isSuccess){HomePage(response, "ok");Console.WriteLine("** - **");Console.WriteLine("用户名为"   user.UserName   "已添加到数据库!!");Console.WriteLine("");}else{HomePage(response, "no");Console.WriteLine("** - **");Console.WriteLine("用户名为"   user.UserName   "添加到数据库失败!!");Console.WriteLine("");}}catch (Exception e){HomePage(response, e.Message);Console.WriteLine("** - **");Console.WriteLine("发生错误,错误原因为"   e.Message);Console.WriteLine("");}}else{HomePage(response, "参数错误!!");Console.WriteLine("** - **");Console.WriteLine("参数错误" );Console.WriteLine("");}return;}public static void OnAccept(IAsyncResult ar){try{Socket socket = ar.AsyncState as Socket;Socket new_client = socket.EndAccept(ar);socket.BeginAccept(new AsyncCallback(OnAccept), socket);byte[] recv_buffer = new byte[1024 * 640];int real_recv = new_client.Receive(recv_buffer);string recv_request = Encoding.UTF8.GetString(recv_buffer, 0, real_recv);Console.WriteLine(recv_request);Resolve(recv_request, new_client);}catch{}}public static void Resolve(string request, Socket response){string[] strs = request.Split(new string[] { "\r\n" }, StringSplitOptions.None);if (strs.Length > 0){string[] items = strs[0].Split(' ');Dictionary<string, string> param = new Dictionary<string, string>();if (strs.Contains("")){string post_data = strs[strs.Length - 1];if (post_data != ""){string[] post_datas = post_data.Split('&');foreach (string s in post_datas){param.Add(s.Split('=')[0], s.Split('=')[1]);}}}Route(items[1], param, response);}}public static void HomePage(Socket response,string result){string statusline = "HTTP/1.1 200 OK\r\n";byte[] statusline_to_bytes = Encoding.UTF8.GetBytes(statusline);string content = result;byte[] content_to_bytes = Encoding.UTF8.GetBytes(content);string header = string.Format("Access-Control-Allow-Origin:*\r\nContent-Type:text/html;charset=UTF-8\r\nContent-Length:{0}\r\n", content_to_bytes.Length);byte[] header_to_bytes = Encoding.UTF8.GetBytes(header);response.Send(statusline_to_bytes);response.Send(header_to_bytes);response.Send(new byte[] { (byte)'\r', (byte)'\n' });response.Send(content_to_bytes);response.Close();}}

  

第三部分 前端页面与Ajax请求

 前端页面设计为:

ajax请求代码:

$('.red_button').click(function () {if (user_Boolean && password_Boolean && varconfirm_Boolean && Mobile_Boolean == true) {$.ajax({type: 'POST',url: 'http://127.0.0.1:8086/',data: {'userName':$('#userName').val(),'psd': $('#psd').val(),'phoneNum': $('#phoneNum').val()},success: function (data) {if (data == "ok") {alert("注册成功!!")} else {alert("data");}}});} else {alert("请完善信息");}
});

 

至此,程序完成.运行程序进行验证.

1:启动服务端程序

 

 

2:启动前端页面,进行数据填写

3 添加结果

 

    至此 ,Demo功能完成。之前没有试过利用Socket技术完成Ajax请求,这次也算是一次尝试,偶尔看到这个程序,以防以后需要 做个笔记..

 

 

 

 

 

 

 

本文转载于:猿2048https://www.mk2048.com/blog/blog.php?id=caichj&title=MySql+Socket 完成数据库的增查Demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果桌面主题_看腻了手机自带的桌面主题,试试这个

在这个看脸的时代&#xff0c;颜值似乎越来越重要了。尤其是我们每天都要看到的手机桌面&#xff0c;如果它的颜值好一点&#xff0c;也许我们的心情会更好&#xff0c;所以有不少人都用手机自带的主题来美化桌面&#xff0c;但是对于喜欢个性的我们&#xff0c;手机自带的主题…

Java SE 11:推动Java向前发展

介绍 在我看来&#xff0c;这篇文章提出了Java语言应该如何发展以保持其作为首选语言的地位。 它还提供了一些我喜欢但有时&#xff08;可能永远不会&#xff09;成为Java一部分的功能&#xff0c;由于我将要解释的某些原因&#xff0c;这些功能有时我已经爱上了。 我真的很想…

Hexo使用细节及各种问题

解决markdown图片不显示(返回403 forbidden)、添加本地图片无法显示、修改文章page模板、同时部署发布同步到多个仓库站点(Github、coding、gitee 码云) 图片不显示 在使用过程中&#xff0c;会发现有的引用图片无法显示的问题。但是如果直接复制图片地址到浏览器打开的话显示…

智能小车37:异常在ARM、JAVA、硬件里的实现

几乎所有编程语言都有异常&#xff0c;可以说有程序就有异常。今天学习Arm的中断(异常)处理,联想到Java的异常,硬件中如何实现等问题&#xff0c;下面给大家分享一下。 一、Arm的中断。 1.触发异常 2.保存现场 3.cpu进入异常工作模式&#xff0c;程序指针(pc)跳入异常入口&…

c++builder提高批量动态创建panel的速度_骑行时影响速度的事项有哪些 怎样有效提高骑行速度 单车租赁信息...

撇开人的因素在自行车的组件中对车速影响最大的几项是什么?车重?自锁?轮组?传动?我的个人感受&#xff0c;从提高幅度上来讲&#xff0c;而不是重要性上来讲一、自锁起码提高你50%的速度&#xff0c;我不用自锁和别人一起走AVS25就很辛苦了&#xff0c;用了自锁&#xff0…

哈希三道题

两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意…

zemax光学设计超级学习手册_穿越十年的一个ZEMAX光学设计案例

目前超过两千人的光学与光学设计方面的微信公众号&#xff0c;欢迎您&#xff01;穿越十年的一个ZEMAX光学设计案例作者&#xff1a;窗台小绿萝CAD&#xff0c;这个词已经深入到学习、工作很多年&#xff0c;翻译过来就是Computer Aided Design&#xff0c;计算机辅助设计。随着…

php基础是什么,php基础学什么?

有不少同学想要学习 PHP&#xff0c;但又不清楚 PHP 基础学什么&#xff0c;那么这篇文章告诉你。熟悉前端开发语言学习 PHP 之前&#xff0c;首先要学习前端语言包括 HTML、CSS、JS 等。等对前端语言有个大致掌握后&#xff0c;能编写一个 web 静态页面。学习 PHP 基本语法和函…

名为 cursor_jinserted 的游标不存在_生鲜电商存在的问题及对策解析:未来生鲜电商如何发展?...

生鲜电商的特点有哪些&#xff1f;生鲜电商特点&#xff1a;1,生鲜电商具有粘性高、重复购买率高、毛利高的“三高”特性&#xff1b;2,生鲜食品需要保鲜、冷藏、冷冻&#xff1b;3,生鲜食品保质期比较短&#xff1b;保存不易、对物流配送的条件要求极高&#xff1b;4,生鲜商品…

番石榴函数和Java 8 Lambdas

我最近阅读了Brian Goetz的《 Lambda的状况》 &#xff0c;在阅读了该文章之后&#xff0c;我想尝试使用Java 8 Lambda表达式。 Brian在他的文章中继续描述了将一种方法称为“功能”接口的接口。 功能接口几乎总是用作匿名类&#xff0c;其中ActionListener是规范示例。 这些“…

关于源码,反码,补码(正数--负数)---------(-128)自己的理解

以一个字节为例 1、无符号位&#xff0c;一个字节可以存放0~255共256个数字&#xff1b;有符号位存放-128~127共256个数字&#xff1b; 2、无符号全都表示为正数&#xff1b;有符号位则首位表示正负数&#xff0c;正数首位为0&#xff0c;负数首位为1&#xff08;因此在判断一个…

英特尔x722网卡驱动_产品详情 | 从核心到边缘,英特尔加速5G网络基础设施建设...

英特尔近期宣布推出无可比拟的5G基础设施芯片产品组合&#xff0c;包括一款面向无线基站的10纳米片上系统(SoC)英特尔凌动P5900&#xff0c;和一款面向5G网络处理的结构化ASIC&#xff0c;一款针对5G网络优化、提供基于GPS的高精度网络服务同步功能的以太网适配器。此外&#x…

canvas离屏技术与放大镜实现

教程所示图片使用的是 github 仓库图片&#xff0c;网速过慢的朋友请移步>>> &#xff08;原文&#xff09;canvas 离屏技术与放大镜实现。 更多讨论或者错误提交&#xff0c;也请移步。 利用canvas除了可以实现滤镜&#xff0c;还可以利用离屏技术放大镜功能。为了方…

使用Ajax的Spring MVC REST调用

这篇文章提供了对Spring MVC Web应用程序的REST调用的简单示例。 它基于在Spring MVC上下文示例中使用Spring MVC服务静态资源和使用Ajax获取JSON 。 该代码可在GitHub的Spring-REST-With-Ajax目录中找到。 主页 我们的主页包含与执行Ajax调用的Javascript函数链接的四个按钮…

linux7系统如何配置网卡,Linux 7 配置网卡(nmcli)

操作系统版本&#xff1a;[rootcjcos01 network-scripts]# cat /etc/redhat-releaseRed Hat Enterprise Linux Server release 7.5 (Maipo)查看网卡、IP等信息&#xff1a;[rootcjcos01 ~]# ifconfigenp0s3: flags4163 mtu 1500inet 192.168.1.90 netmask 255.255.255.0 bro…

学以致用深入浅出数字信号处理 pdf_数字阵列雷达--相控阵专题讲座之三

数字阵列雷达-相控阵专题讲座之三https://www.zhihu.com/video/1218562626877583360从名词上看&#xff0c;数字阵列雷达&#xff0c;肯定是阵列雷达了&#xff0c;那么数字阵列与传统的相控阵雷达又有什么区别呢&#xff1f;传统的相控阵雷达&#xff0c;是依靠移相器、衰减器…

Ubuntu中右击出现终端

1 root用户 $sudo apt-get install nautilus-open-terminal 2重启 3ok 转载于:https://www.cnblogs.com/lanjianhappy/p/6761599.html

使用bootstrap的dropdown部件时报错:error:Bootstrap dropdown require Popper.js

前言&#xff1a;前端小白一枚&#xff0c;刚注册博客&#xff0c;先发个学习过程中新碰到小问题试试水吧~ 摘要&#xff1a;最近在学习bootstrap&#xff0c;偶然碰到了一个小问题&#xff0c;bootstrap网站也没有做过多的解释&#xff0c;今天分享给大家。 问题描述&#x…

C#中的三层

三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为&#xff1a;界面层&#xff08;User Interface layer&#xff09;、业务逻辑层&#xff08;Business Logic Layer&#xff09;、数据访问层&#xff08;Data access layer&#xff09;。区分层次的…

研究僵局–第3部分

在本系列的前两个博客&#xff08; 第1部分和第2部分&#xff09;中 &#xff0c;我演示了如何创建一段死锁的不良代码&#xff0c;然后使用该代码展示了进行线程转储的三种方式。 在这个博客中&#xff0c;我将分析线程转储以找出错误的原因。 下面的讨论同时涉及本系列第1部…