对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。

在今日的企业环境中,把面向对象软件和关系数据库一起使用可能是相当麻烦和浪费时间的,ORM

 

不仅仅管理.NET类到数据库表的映射(包括.NET 数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,可以大幅度减少开发时人工使用SQL和ADO.NET处理数据的时间。

现在有很多成熟的开源框架支持ORM,如:NHibernate,PDO....等 但是他们内部是怎么实现的, 通过一个非常简单的实例让我们一起来探索其中最为关键的过程. (适合ORM初学者)我们以Sql Server 为例

定义操作类型枚举, 为增强可读性 将枚举名使用中文,在实际应用中不建议使用中文作为枚举名称。

  1. public class DataMessageClass
  2. {
  3. public enum DataMessage
  4. {
  5. 数据连接失败,系统忙请等待,操作成功,可继续操作
  6. }
  7. }

标记实体映射基类

  1. /// <summary>
  2. /// DataBase 的摘要说明。
  3. /// </summary>
  4. public interface IDataBase
  5. {
  6. }

自定义属性类,DataObjectAttribute 用于标记映射实体所对应的数据表 FieldObjectAttribute用于标记字段所代表的特殊属性

需要的对数据库表和字段的简单表示我们都有了,下一步来实现对Sql Server 数据表的,Select ,Update,Insert 等操作,ORM映射实现类。

 public class DataAccess
{
private static string mConnectStr=string.Empty;
private static System.Data.SqlClient.SqlConnection mSqlConnect; //连接
private static System.Data.SqlClient.SqlCommand mSqlCmd; // 执行命令
private static System.Data.SqlClient.SqlDataAdapter mDataAdapter; //装配件
private const string mConnectKey="TestConnect"; // 数据库连接字符串键名
public DataAccess()
{
try
{
//
// TODO: 在此处添加构造函数逻辑
//
mConnectStr=GetConnectValue();
mSqlConnect= new SqlConnection(mConnectStr);
mSqlConnect.Open();
}
catch
{
mSqlConnect= new SqlConnection(mConnectStr);
}
}
public void Close()
{
if (mSqlConnect != null && mSqlConnect.State != ConnectionState.Closed)
{
mSqlConnect.Close();
}
}
/// <summary>
/// 初始化数据连接对象
/// </summary>
/// <param name="ConnectStr"></param>
public DataAccess(string ConnectStr)
{
//
// TODO: 在此处添加构造函数逻辑
//
mConnectStr=ConnectStr;
mSqlConnect= new SqlConnection(mConnectStr);
mSqlConnect.Open();
}
/// <summary>
/// 获得连接字符串的值
/// </summary>
/// <returns></returns>
private string GetConnectValue()
{
return System.Configuration.ConfigurationSettings.AppSettings[mConnectKey].ToString();
}
private DataMessageClass.DataMessage CheckOpenState()
{
if(mSqlConnect.State==System.Data.ConnectionState.Broken || mSqlConnect.State==System.Data.ConnectionState.Closed)
{
mSqlConnect.Close();
mSqlConnect.ConnectionString = mConnectStr;
try
{
lock(mSqlConnect)
{
mSqlConnect.Open();
}
}
catch(System.Exception ex)
{
return DataMessageClass.DataMessage.数据连接失败;
}
}
if(mSqlConnect.State==System.Data.ConnectionState.Executing || mSqlConnect.State==System.Data.ConnectionState.Fetching || mSqlConnect.State==System.Data.ConnectionState.Connecting)
{
return DataMessageClass.DataMessage.系统忙请等待;
}
return DataMessageClass.DataMessage.可继续操作;
}
/// <summary>
/// 执行Sql语句 带参数
/// </summary>
/// <param name="ExeSqlStr">语句</param>
/// <param name="ExeSqlParameter">参数</param>
/// <returns></returns>
public DataMessageClass.DataMessage ExeSQL(string ExeSqlStr,System.Data.SqlClient.SqlParameter[] ExeSqlParameter)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(ExeSqlStr,mSqlConnect);
foreach(System.Data.SqlClient.SqlParameter tParameter in ExeSqlParameter)
{
if(tParameter!=null){mSqlCmd.Parameters.Add(tParameter);}
}
mSqlCmd.ExecuteNonQuery();
}
return DataMessageClass.DataMessage.操作成功;
}
/// <summary>
/// 执行Sql语句 不带参数
/// </summary>
/// <param name="ExeSqlStr">语句</param>
/// <returns></returns>
public DataMessageClass.DataMessage ExeSQL(string ExeSqlStr)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(ExeSqlStr,mSqlConnect);
mSqlCmd.ExecuteNonQuery();
}
return DataMessageClass.DataMessage.操作成功;
}
/// <summary>
/// 执行Sql语句 不带参数 返回一个值
/// </summary>
/// <param name="ExeSqlStr">语句</param>
/// <returns></returns>
public object ExeSQLReturnValue(string ExeSqlStr,System.Data.SqlClient.SqlParameter[] ExeSqlParameter)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(ExeSqlStr,mSqlConnect);
foreach(System.Data.SqlClient.SqlParameter tParameter in ExeSqlParameter)
{
if(tParameter!=null){mSqlCmd.Parameters.Add(tParameter);};
}
return mSqlCmd.ExecuteScalar();
}
return null;
}
/// <summary>
/// 执行Sql语句 不带参数 返回一个值
/// </summary>
/// <param name="ExeSqlStr">语句</param>
/// <returns></returns>
public object ExeSQLReturnValue(string ExeSqlStr)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(ExeSqlStr,mSqlConnect);
return mSqlCmd.ExecuteScalar();
}
return null;
}
/// <summary>
/// 获得查询表记录 带参数
/// </summary>
/// <param name="SelSqlStr">语句</param>
/// <param name="SelSqlParameter">参数</param>
/// <returns>数据集合</returns>
public System.Data.DataSet GetSelectRow(string SelSqlStr,System.Data.SqlClient.SqlParameter[] SelSqlParameter)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(SelSqlStr,mSqlConnect);
foreach(System.Data.SqlClient.SqlParameter tParameter in SelSqlParameter)
{
if(tParameter!=null){mSqlCmd.Parameters.Add(tParameter);};
}
// 装入数据
System.Data.DataSet TempDataSet = new DataSet();
mDataAdapter=new SqlDataAdapter(mSqlCmd);
mDataAdapter.Fill(TempDataSet);
return TempDataSet;
}
return null;
}
/// <summary>
/// 获得查询表记录 不带参数
/// </summary>
/// <param name="SelSqlStr">语句</param>
/// <returns>set数据集合</returns>
public System.Data.DataSet GetSelectRow(string SelSqlStr)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(SelSqlStr,mSqlConnect);
// 装入数据
System.Data.DataSet TempDataSet = new DataSet();
mDataAdapter=new SqlDataAdapter(mSqlCmd);
mDataAdapter.Fill(TempDataSet);
return TempDataSet;
}
return null;
}
/// <summary>
/// 获得查询表记录 不带参数
/// </summary>
/// <param name="SelSqlStr">语句</param>
/// <returns>Reader数据集合</returns>
public System.Data.SqlClient.SqlDataReader GetSelectRowReader(string SelSqlStr)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(SelSqlStr,mSqlConnect);
// 装入数据
System.Data.SqlClient.SqlDataReader TDataReader;
TDataReader=mSqlCmd.ExecuteReader();
return TDataReader;
}
return null;
}
/// <summary>
/// 分页读取
/// </summary>
/// <param name="SqlStr">语句</param>
/// <param name="SelSqlParameter">参数</param>
/// <param name="DataSetName">名称</param>
/// <param name="PageIndex">当前页面</param>
/// <param name="MaxReocrd">记录数</param>
/// <returns></returns>
public System.Data.DataSet GetPageDataSet(string SqlStr,System.Data.SqlClient.SqlParameter[] SelSqlParameter,string DataSetName,int PageIndex,int MaxReocrd)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(SqlStr,mSqlConnect);
foreach(System.Data.SqlClient.SqlParameter tParameter in SelSqlParameter)
{
if(tParameter!=null){mSqlCmd.Parameters.Add(tParameter);};
}
// 装入数据
System.Data.DataSet TempDataSet = new DataSet();
mDataAdapter=new SqlDataAdapter(mSqlCmd);
mDataAdapter.Fill(TempDataSet,(PageIndex-) * MaxReocrd, MaxReocrd,DataSetName);
return TempDataSet;
}
return null;
}
/// <summary>
/// 分页读取 不带参数
/// </summary>
/// <param name="SqlStr">语句</param>
/// <param name="SelSqlParameter">参数</param>
/// <param name="DataSetName">名称</param>
/// <param name="PageIndex">当前页面</param>
/// <param name="MaxReocrd">记录数</param>
/// <returns></returns>
public System.Data.DataSet GetPageDataSet(string SqlStr,string DataSetName,int PageIndex,int MaxReocrd)
{
DataMessageClass.DataMessage tDataMessage;
tDataMessage=CheckOpenState();
if (tDataMessage==DataMessageClass.DataMessage.可继续操作)
{
mSqlCmd=new SqlCommand(SqlStr,mSqlConnect);
// 装入数据
System.Data.DataSet TempDataSet = new DataSet();
mDataAdapter=new SqlDataAdapter(mSqlCmd);
mDataAdapter.Fill(TempDataSet,(PageIndex-) * MaxReocrd, MaxReocrd,DataSetName);
return TempDataSet;
}
return null;
}
/// <summary>
/// 获得一个对象
/// </summary>
/// <param name="TDataBase"></param>
public IDataBase GetOnlyObject(IDataBase TDataBase)
{
// 生成条件
DataObjectAttribute TDataObject =TDataBase.GetType().GetCustomAttributes(typeof(DataObjectAttribute),false)[] as DataObjectAttribute;
string[] KeyS= TDataObject.KeyS.Split(new char[]{','});
string TableName =TDataObject.Table;
System.Data.SqlClient.SqlParameter[] TSqlParameter=new SqlParameter[KeyS.Length];
System.Reflection.FieldInfo[] mFieldInfo=TDataBase.GetType().GetFields();
string SelSql="Select * From " + TableName + " ";
for (byte index=; index<KeyS.Length;index++)
{
if (index==)
SelSql += " Where " + KeyS[index] + " = @" + KeyS[index] + " " ;
else
SelSql += " and " + KeyS[index] + " = @" + KeyS[index] + " " ;
TSqlParameter[index]=new SqlParameter("@" + KeyS[index] ,TDataBase.GetType().GetField(KeyS[index]).GetValue(TDataBase));
}
// 得到记录
System.Data.DataSet TDataSet= new DataSet();
TDataSet=GetSelectRow(SelSql,TSqlParameter);
if (TDataSet.Tables[].Rows.Count ==) {return null;}
// 把数据分配到字段
foreach (System.Reflection.FieldInfo TFieldInfo in mFieldInfo)
{
TDataBase.GetType().GetField(TFieldInfo.Name).SetValue(TDataBase,TDataSet.Tables[].Rows[][TFieldInfo.Name]==System.DBNull.Value ? GetTypeValue(TFieldInfo.FieldType) :TDataSet.Tables[].Rows[][TFieldInfo.Name]);
}
return TDataBase;
}
/// <summary>
/// 得到初始值
/// </summary>
/// <param name="TType"></param>
/// <returns></returns>
private object GetTypeValue(System.Type TType)
{
if(TType.FullName.Equals(System.TypeCode.DateTime.GetType()))
{
return System.DateTime.Now;
}
return null;
}
/// <summary>
/// 添加一个对象
/// </summary>
/// <param name="TDataBase"></param>
public object AddOnlyObjectReturnIndex(IDataBase TDataBase)
{
DataObjectAttribute TDataObject =TDataBase.GetType().GetCustomAttributes(typeof(DataObjectAttribute),false)[] as DataObjectAttribute;
string[] KeyS= TDataObject.KeyS.Split(new char[]{','});
string TableName =TDataObject.Table;
System.Reflection.FieldInfo[] mFieldInfo=TDataBase.GetType().GetFields();
System.Data.SqlClient.SqlParameter[] TSqlParameter=new SqlParameter[mFieldInfo.Length];
string SelSql="insert into " + TableName + " ";
string FieldName =string.Empty;
string ValueName =string.Empty;
for (byte index= ; index <mFieldInfo.Length ; index ++)
{
if(mFieldInfo[index].GetCustomAttributes(typeof(FieldObjectAttribute),false).Length!=)
{
FieldObjectAttribute TFieldObject =mFieldInfo[index].GetCustomAttributes(typeof(FieldObjectAttribute),false)[] as FieldObjectAttribute;
if (TFieldObject.Type==)
{
FieldName += FieldName.Length > ? "," + mFieldInfo[index].Name : mFieldInfo[index].Name ;
ValueName += ValueName.Length > ? "," + "@" + mFieldInfo[index].Name : "@" + mFieldInfo[index].Name ;
TSqlParameter[index]=new SqlParameter("@" + mFieldInfo[index].Name ,System.Guid.NewGuid().ToString());
}
else if (TFieldObject.Type==)
{
// 此字段为自增列放弃
}
}
else
{
FieldName += FieldName.Length > ? "," + mFieldInfo[index].Name : mFieldInfo[index].Name ;
ValueName += ValueName.Length > ? "," + "@" + mFieldInfo[index].Name : "@" + mFieldInfo[index].Name ;
TSqlParameter[index]=new SqlParameter("@" + mFieldInfo[index].Name ,TDataBase.GetType().GetField(mFieldInfo[index].Name).GetValue(TDataBase));
}
}
SelSql += " (" + FieldName + ") VALUES (" + ValueName + ") SELECT @@IDENTITY AS 'Identity'";
return ExeSQLReturnValue(SelSql,TSqlParameter);
}
/// <summary>
/// 添加一个对象
/// </summary>
/// <param name="TDataBase"></param>
public void AddOnlyObject(IDataBase TDataBase)
{
DataObjectAttribute TDataObject =TDataBase.GetType().GetCustomAttributes(typeof(DataObjectAttribute),false)[] as DataObjectAttribute;
string[] KeyS= TDataObject.KeyS.Split(new char[]{','});
string TableName =TDataObject.Table;
System.Reflection.FieldInfo[] mFieldInfo=TDataBase.GetType().GetFields();
System.Data.SqlClient.SqlParameter[] TSqlParameter=new SqlParameter[mFieldInfo.Length];
string SelSql="insert into " + TableName + " ";
string FieldName =string.Empty;
string ValueName =string.Empty;
for (byte index= ; index <mFieldInfo.Length ; index ++)
{
if(mFieldInfo[index].GetCustomAttributes(typeof(FieldObjectAttribute),false).Length!=)
{
FieldObjectAttribute TFieldObject =mFieldInfo[index].GetCustomAttributes(typeof(FieldObjectAttribute),false)[] as FieldObjectAttribute;
if (TFieldObject.Type==)
{
FieldName += FieldName.Length > ? "," + mFieldInfo[index].Name : mFieldInfo[index].Name ;
ValueName += ValueName.Length > ? "," + "@" + mFieldInfo[index].Name : "@" + mFieldInfo[index].Name ;
TSqlParameter[index]=new SqlParameter("@" + mFieldInfo[index].Name ,System.Guid.NewGuid().ToString());
}
else if (TFieldObject.Type==)
{
// 此字段为自增列放弃
}
}
else
{
FieldName += FieldName.Length > ? "," + mFieldInfo[index].Name : mFieldInfo[index].Name ;
ValueName += ValueName.Length > ? "," + "@" + mFieldInfo[index].Name : "@" + mFieldInfo[index].Name ;
TSqlParameter[index]=new SqlParameter("@" + mFieldInfo[index].Name ,TDataBase.GetType().GetField(mFieldInfo[index].Name).GetValue(TDataBase));
}
}
SelSql += " (" + FieldName + ") VALUES (" + ValueName + ")";
ExeSQL(SelSql,TSqlParameter);
}
/// <summary>
/// 更新一个对象
/// </summary>
/// <param name="TDataBase"></param>
public void UpdateOnlyObject(IDataBase TDataBase)
{
DataObjectAttribute TDataObject =TDataBase.GetType().GetCustomAttributes(typeof(DataObjectAttribute),false)[] as DataObjectAttribute;
string[] KeyS= TDataObject.KeyS.Split(new char[]{','});
Array TArray = Array.CreateInstance(typeof(string),KeyS.Length);
KeyS.CopyTo(TArray,);
string TableName =TDataObject.Table;
System.Reflection.FieldInfo[] mFieldInfo=TDataBase.GetType().GetFields();
System.Data.SqlClient.SqlParameter[] TSqlParameter=new SqlParameter[mFieldInfo.Length];
string SelSql="Update " + TableName + " Set ";
string FieldValueName =string.Empty;
string WhereName = string.Empty;
for (byte index= ; index <mFieldInfo.Length ; index ++)
{
if(mFieldInfo[index].GetCustomAttributes(typeof(FieldObjectAttribute),false).Length!=)
{
FieldObjectAttribute TFieldObject =mFieldInfo[index].GetCustomAttributes(typeof(FieldObjectAttribute),false)[] as FieldObjectAttribute;
if (TFieldObject.Type==)
{
TSqlParameter[index]=new SqlParameter("@" + mFieldInfo[index].Name ,TDataBase.GetType().GetField(mFieldInfo[index].Name).GetValue(TDataBase));
}
}
else
{
if(Array.IndexOf(TArray,mFieldInfo[index].Name)==-)
{
FieldValueName += FieldValueName.Length > ? ", " + mFieldInfo[index].Name + "=@" + mFieldInfo[index].Name : mFieldInfo[index].Name + "=@" + mFieldInfo[index].Name;
}
TSqlParameter[index]=new SqlParameter("@" + mFieldInfo[index].Name ,TDataBase.GetType().GetField(mFieldInfo[index].Name).GetValue(TDataBase));
}
}
for (byte index=; index<KeyS.Length;index++)
{
WhereName += WhereName.Length> ? " and " + KeyS[index] + " = @" + KeyS[index] :" Where " + KeyS[index] + " = @" + KeyS[index] ;
}
SelSql += FieldValueName + WhereName;
ExeSQL(SelSql,TSqlParameter);
}
/// <summary>
/// 删除一个对象
/// </summary>
/// <param name="TDataBase"></param>
public void DelOnlyObject(IDataBase TDataBase)
{
DataObjectAttribute TDataObject =TDataBase.GetType().GetCustomAttributes(typeof(DataObjectAttribute),false)[] as DataObjectAttribute;
string[] KeyS= TDataObject.KeyS.Split(new char[]{','});
string TableName =TDataObject.Table;
System.Reflection.FieldInfo[] mFieldInfo=TDataBase.GetType().GetFields();
System.Data.SqlClient.SqlParameter[] TSqlParameter=new SqlParameter[KeyS.Length];
string SelSql="delete " + TableName ;
string FieldValueName =string.Empty;
for (byte index=; index<KeyS.Length;index++)
{
FieldValueName += FieldValueName.Length> ? " and " + KeyS[index] + " = @" + KeyS[index] :" Where " + KeyS[index] + " = @" + KeyS[index] ;
TSqlParameter[index]=new SqlParameter("@" + KeyS[index] ,TDataBase.GetType().GetField(KeyS[index]).GetValue(TDataBase));
}
SelSql+=FieldValueName;
ExeSQL(SelSql,TSqlParameter);
}
}
 

实现就这么简单了,让我们测试其使用过程。

第一步:定义数据映射实体

 /// <summary>
/// "UserInfo" 标示目标表名
/// "Guid" 代表主键, 可以通过逗号分隔来指定多个主键
/// </summary>
[DataAccess.DataObject("UserInfo", "Guid")]
public class UserInfo : IDataBase
{
/// <summary>
/// FieldObject(0) 标示GUID 类型的主键,FieldObject(1) 标示自增性主键
/// </summary>
[FieldObject()]
public string Guid = string.Empty;
public string UserName = string.Empty;
public string UserEMail = string.Empty;
public string UserTel = string.Empty;
public string UserSex = string.Empty;
public string UserDec = string.Empty;
public string RegIpAddres = string.Empty;
}

第二步:配置连接字符串

 <appSettings>
<add key ="ORMConnect" value ="Data Source=???.??.??.???,1433;Initial Catalog=?????;Persist Security Info=True;User ID=?????;Password=??????"/>
</appSettings >

第三步:测试对数据表的操作

 [c-sharp] view plaincopyprint?

 DataAccess.DataAccess ormAccess= new DataAccess.DataAccess();

 UserInfo info = new UserInfo();
info.UserName = "TestUser" ; info.UserDec = http://www.apace.com.cn; info.UserEMail = G_Jack@.com;
info.UserTel = "";
info.RegIpAddres = “testip”; //测试新增 ormAccess.AddOnlyObject(info); //测试更新 ormAccess.UpdateOnlyObject(info) //测试删除 ormAccess.DelOnlyObject(info)

对ORM的简单实现就到处结束了,希望能帮到大家

C# ORM简单原理的更多相关文章

  1. java中异常处理机制的简单原理

    以上是自认为的java异常处理的简单原理,如有不妥之处还请各位大神帮忙指点,谢谢!

  2. java——关于异常处理机制的简单原理和应用

    异常处理机制的简单原理和应用 一.Execption可以分为java标准定义的异常和程序员自定义异常2种 (1)一种是当程序违反了java语规则的时候,JAVA虚拟机就会将发生的错误表示为一个异常.这 ...

  3. javascript AJAX简单原理及什么是ajax

    AJAX简单原理供初学者理解 AJAX的原理: Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面.这其 ...

  4. ORM实现原理

    1.什么是ORM ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的 ...

  5. js编译器的一些简单原理

    有没有发现在写代码的时候,往往会遇到一些莫名其妙的错误,然后时间紧急不得不去网上查阅一些代码.虽然要实现的功能解决了,但是看被拷贝的代码好多真心看不懂,以后遇到诸如此类的问题,如果查阅不到这些代码的话 ...

  6. 为初学者写ORM,ORM的原理及测试案例

    提纲 一.什么是ORM.二.反射以及Attribute在ORM中的应用.三.创建一个数据库表和表对应的实体model.四.实体model如何映射出数据库表.五.组合ORM映射生成insert语句.六. ...

  7. Spring MVC简单原理

    Spring MVC原理 针对有Java Web基础.Spring基础和Spring MVC使用经验者. 前言 目前基于Java的web后端,Spring生态应该是比较常见了.虽然现在流行前后端分离, ...

  8. Android开发学习之路--RxAndroid之简单原理

      学习了RxAndroid,其实也就是RxJava了,但是还是不是非常清楚到底RxAndroid有什么用呢?为什么要使用RxAndroid呢?这篇文章讲得不错,RxJava的原理.但是这里还是把整个 ...

  9. go 利用orm简单实现接口分布式锁

    在开发中有些敏感接口,例如用户余额提现接口,需要考虑在并发情况下接口是否会发生问题.如果用户将自己的多条提现请求同时发送到服务器,代码能否扛得住呢?一旦没做锁,那么就真的会给用户多次提现,给公司带来损 ...

随机推荐

  1. FastDFS结合FastDHT实现文件去重存储

    存储文件时,为了节省存储空间,需要实现文件去重,即同一份文件只在服务器上存储一份.一种实现是文件上传后先落到应用服务器上,计算MD5并存储到数据库中,然后决定是否上传存储服务器.这样做的缺点是应用服务 ...

  2. LOG4NET图文教程

    LOG4NET教程 一:简介 从操作系统到大多数的大型软件,都会有自己的程序运行时的日志跟踪API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而软件开发人员需要一套强大的日志系统来记 ...

  3. 前端 JS 修炼(第一天)包装对象、作用域、创建对象

    1.js基本概念以及注意 直接量 :程序中直接使用的数据值.下面列出的都是直接量: 1 12 //数字 2 1.2 //小数 3 "hello world" //字符串文本 4 t ...

  4. kubernetes实战篇之nexus oss服务器部署及基于nexus的docker镜像仓库搭建

    系列目录 Nexus oss仓库管理平台搭建 Nexus是一款仓库管理工具,支持Npm,bower,maven,nuget,apt,yum甚至docker,helm等各种仓库,说的通俗以下,就是私服镜 ...

  5. DOM模型-属性操作

    HTML 元素包括标签名和若干个键值对,这个键值对就称为"属性"(attribute)."属性"本身是一个对象(Attr对象),但是实际上,这个对象极少使用.一 ...

  6. Hadoop —— 单机环境搭建

    一.前置条件 Hadoop的运行依赖JDK,需要预先安装,安装步骤见: Linux下JDK的安装 二.配置免密登录 Hadoop组件之间需要基于SSH进行通讯. 2.1 配置映射 配置ip地址和主机名 ...

  7. 统一资源定位符URL

    Uniform Resource Locate--URL 用途:通过URL访问web网页:通过URL使用其它的Internet应用程序,例如FTP,Telnet(远程登录服务):对应IE浏览器窗口中的 ...

  8. 22 | 从0到1:API测试怎么做?常用API测试工具简介

  9. Rxjs中Notification 介绍

    timer(0, 1000) // 计时器,每1000ms发射一个值,初始发射值延迟时间为0s: .pipe( take(5), // 取前5个值 takeWhile(value => valu ...

  10. Linux 安装Nginx与使用

    最近继续整理Linux相关文档.这次整理的是Nginx,这里将自己整理的详细文档做个笔记. 1.  安装环境依赖包 1. gcc 语言编译器套件. 2. pcre 兼容正则表达式的库 rewrite ...