用C#实现对MSSqlServer数据库的增删改查---DAL层
说明:本人完成的工作是对传感器--超声波物位计进行硬件集成,上位机通过串口接收传感器数据并将其存到数据库中;在DAL层实现对数据库的增删改查,其中包含两个数据表分别是WaterLevelSet表和WaterLevelRecord表,以下代码即是完成对两张表进行数据操作。
/*----------------------------------------------------------------
// Copyright (C) 2013 *************
// 版权所有。
//
// 文件名:WaterLevelDao.cs
// 文件功能描述:定义水位计设置信息相关的数据访问对象
//
// 创建标识:2013-9-22
//
// 修改标识:2013-9-23
// 修改描述:添加GetAllWaterLevelSetInfo,AddWaterLevelSetInfo,
//ModifyWaterLevelSetInfo,DelWaterLevelSetInfo等方法
//
// 修改标识:2013-9-24
// 修改描述:修改可空字段的数据绑定
//修改标识:2013-9-26
// 修改描述:修改AddWaterLevelSet,去掉SELECT @@IDENTITY
//
//----------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SMOS.Model.Device;
using System.Data.SqlClient;
using System.Data; namespace SMOS.DAL.Device
{
public class WaterLevelSetDao
{
/// <summary>
/// 根据设备ID获取水位计设置信息
/// </summary>
/// <param name="deviceID"></param>
/// <returns>水位计设置信息</returns>
public WaterLevelSetInfo GetWaterLevelSetInfo(int deviceID)
{
string sql =
@"select t.DeviceID,t.BaseLevel,t.Remark,t.Port,
t.BaudRate,t.DataBites,t.ParityBit,t.StopBits,t.AcquisitionInterval,
t.ConnectType,t.CreateBy,t.CreateTime,t.UpdateBy,t.UpdateTime
from dbo.WaterLevelSet t(nolock)
where t.DeviceID=@DeviceID"; IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = deviceID}
}; WaterLevelSetInfo entity = null;
DataSet ds = DBHelper.ExecuteDataset(sql,paras.ToArray()); if (ds == null || ds.Tables.Count <= || ds.Tables[].Rows.Count <= )
return entity;
return DataRowBinding(ds.Tables[].Rows[]);
}
/// <summary>
/// 获取所有水位计设置信息
/// </summary>
/// <returns>水位计设置列表</returns>
public IList<WaterLevelSetInfo> GetAllWaterLevelSetInfo()
{
string sql =
@"select t.DeviceID,t.BaseLevel,t.Remark,t.Port,
t.BaudRate,t.DataBites,t.ParityBit,t.StopBits,t.AcquisitionInterval,
t.ConnectType,t.CreateBy,t.CreateTime,t.UpdateBy,t.UpdateTime
from dbo.WaterLevelSet t(nolock)
where 1=1";
IList<WaterLevelSetInfo> lstWaterLevelSetInfo = new List<WaterLevelSetInfo>();
DataSet ds = DBHelper.ExecuteDataset(sql);
if (ds == null || ds.Tables.Count <= )
return lstWaterLevelSetInfo;
foreach (DataRow dr in ds.Tables[].Rows)
{
WaterLevelSetInfo entity = DataRowBinding(dr);
if (entity != null)
lstWaterLevelSetInfo.Add(entity);
}
return lstWaterLevelSetInfo;
}
/// <summary>
/// 增加水位计设置信息
/// </summary>
/// <param name="waterLevelSetInfo">水位计设置信息</param>
/// <returns>操作记录数</returns>
public int AddWaterLevelSetInfo(WaterLevelSetInfo waterLevelSetInfo)
{
if (waterLevelSetInfo == null)
{
return ;
}
string sql=
@"INSERT INTO dbo.WaterLevelSet
(DeviceID,BaseLevel,Remark,Port,BaudRate,
DataBites,ParityBit,StopBits,AcquisitionInterval,
ConnectType,CreateBy,CreateTime
)
VALUES
(@DeviceID,@BaseLevel,@Remark,@Port,@BaudRate,
@DataBites,@ParityBit,@StopBits,@AcquisitionInterval,
@ConnectType,@CreateBy,@CreateTime
)";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = waterLevelSetInfo.DeviceID},
new SqlParameter("@BaseLevel",SqlDbType.Decimal){Value = waterLevelSetInfo.BaseLevel},
new SqlParameter("@Remark",SqlDbType.NVarChar,){Value = waterLevelSetInfo.Remark},
new SqlParameter("@Port",SqlDbType.Int){Value = waterLevelSetInfo.Port},
new SqlParameter("@BaudRate",SqlDbType.Int){Value = waterLevelSetInfo.BaudRate},
new SqlParameter("@DataBites",SqlDbType.Int){Value = waterLevelSetInfo.DataBits},
new SqlParameter("@ParityBit",SqlDbType.Int){Value = waterLevelSetInfo.ParityBit},
new SqlParameter("@StopBits",SqlDbType.Int){Value = waterLevelSetInfo.StopBits},
new SqlParameter("@AcquisitionInterval",SqlDbType.Int){Value = waterLevelSetInfo.AcquisitionInterval},
new SqlParameter("@ConnectType",SqlDbType.TinyInt){Value = waterLevelSetInfo.ConnectType.GetHashCode()},
new SqlParameter("@CreateBy",SqlDbType.NVarChar,){Value = Global.GlobalInfo.loginInfo.LoginAccount},
new SqlParameter("@CreateTime",SqlDbType.DateTime){Value = DateTime.Now},
}; return DBHelper.ExecuteNonQuery(sql, paras.ToArray());
}
/// <summary>
/// 修改水位计设置信息
/// </summary>
/// <param name="waterLevelSetInfo">水位计设置信息</param>
/// <returns>操作记录</returns>
public int ModifyWaterLevelSetInfo(WaterLevelSetInfo waterLevelSetInfo)
{
if (waterLevelSetInfo == null)
{
return ;
}
string sql =
@"UPDATE dbo.WaterLevelSet
SET DeviceID=@DeviceID
,BaseLevel=@BaseLevel
,Remark=@Remark
,Port=@Port
,BaudRate=@BaudRate
,DataBites=@DataBites
,ParityBit=@ParityBit
,StopBits=@StopBits
,AcquisitionInterval=@AcquisitionInterval
,ConnectType=@ConnectType
,UpdateBy=@UpdateBy
,UpdateTime=@UpdateTime
WHERE DeviceID=@DeviceID";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = waterLevelSetInfo.DeviceID},
new SqlParameter("@BaseLevel",SqlDbType.Decimal){Value = waterLevelSetInfo.BaseLevel},
new SqlParameter("@Remark",SqlDbType.NVarChar,){Value = waterLevelSetInfo.Remark},
new SqlParameter("@Port",SqlDbType.Int){Value = waterLevelSetInfo.Port},
new SqlParameter("@BaudRate",SqlDbType.Int){Value = waterLevelSetInfo.BaudRate},
new SqlParameter("@DataBites",SqlDbType.Int){Value = waterLevelSetInfo.DataBits},
new SqlParameter("@ParityBit",SqlDbType.Int){Value = waterLevelSetInfo.ParityBit},
new SqlParameter("@StopBits",SqlDbType.Int){Value = waterLevelSetInfo.StopBits},
new SqlParameter("@AcquisitionInterval",SqlDbType.Int){Value = waterLevelSetInfo.AcquisitionInterval},
new SqlParameter("@ConnectType",SqlDbType.TinyInt){Value = waterLevelSetInfo.ConnectType.GetHashCode()},
new SqlParameter("@UpdateBy",SqlDbType.NVarChar,){Value = Global.GlobalInfo.loginInfo.LoginAccount},
new SqlParameter("@UpdateTime",SqlDbType.DateTime){Value = DateTime.Now},
};
return DBHelper.ExecuteNonQuery(sql, paras.ToArray());
}
/// <summary>
/// 删除水位计设置信息
/// </summary>
/// <param name="waterLevelSetInfo">水位计设置信息</param>
/// <returns>操作记录</returns>
public int DelWaterLevelSetInfo(WaterLevelSetInfo waterLevelSetInfo)
{
if (waterLevelSetInfo == null)
{
return ;
}
string sql =
@"DELETE FROM dbo.WaterLevelSet
WHERE DeviceID = @DeviceID";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = waterLevelSetInfo.DeviceID },
}; return DBHelper.ExecuteNonQuery(sql, paras.ToArray());
}
#region 数据绑定
private WaterLevelSetInfo DataRowBinding(DataRow dr)
{
if (dr == null)
{
return null;
} WaterLevelSetInfo entity = new WaterLevelSetInfo();
entity.DeviceID = Convert.ToInt32(dr["DeviceID"]);
entity.BaseLevel = Convert.ToDecimal(dr["BaseLevel"]); if (dr["Remark"] != DBNull.Value)
{
entity.Remark = dr["Remark"].ToString();
}
else
{
entity.Remark = string.Empty;
}
entity.Port = Convert.ToInt32(dr["Port"]);
entity.BaudRate = Convert.ToInt32(dr["BaudRate"]);
if (dr["DataBites"] != DBNull.Value)
{
entity.DataBits = Convert.ToInt32(dr["DataBites"]);
}
if (dr["ParityBit"] != DBNull.Value)
{
entity.ParityBit = Convert.ToInt32(dr["ParityBit"]);
}
if (dr["StopBits"] != DBNull.Value)
{
entity.StopBits = Convert.ToInt32(dr["StopBits"]);
}
if (dr["AcquisitionInterval"] != DBNull.Value)
{
entity.AcquisitionInterval = Convert.ToInt32(dr["AcquisitionInterval"]);
}
if (dr["ConnectType"] != DBNull.Value)
{
entity.ConnectType = SMOS.Model.Eunm.ConvertToEnum<SMOS.Model.Eunm.DeviceConnectType>(dr["ConnectType"]);
}
if (dr["CreateBy"] != DBNull.Value)
{
entity.CreateBy = dr["CreateBy"].ToString();
}
else
{
entity.CreateBy = string.Empty;
}
entity.CreateTime = Convert.ToDateTime(dr["CreateTime"]);
if (dr["UpdateBy"] != DBNull.Value)
{
entity.UpdateBy = dr["UpdateBy"].ToString();
}
else
{
entity.UpdateBy = string.Empty;
}
if (dr["UpdateTime"] != DBNull.Value)
{
entity.UpdateTime = Convert.ToDateTime(dr["UpdateTime"]);
}
return entity;
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SMOS.Model.Device;
using System.Data.SqlClient;
using System.Data; namespace SMOS.DAL.Device
{
public class WaterLevelRecordDao
{
/// <summary>
/// 查出水位计记录信息的最后一条记录
/// </summary>
/// <param name="deviceID">设备ID</param>
/// <returns>操作记录</returns>
public WaterLevelRecordInfo GetLastWaterLevelRecordInfo(int deviceID)
{
string sql =
@"select top 1
t.RecordID,t.DeviceID,t.MeasuredLevel,t.RecordTime,
t.CreateBy,t.CreateTime,t.Remark
from dbo.WaterLevelRecord t(nolock)
where t.DeviceID=@DeviceID
order by t.CreateTime desc"; IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = deviceID}
}; WaterLevelRecordInfo entity = null;
DataSet ds = DBHelper.ExecuteDataset(sql, paras.ToArray()); if (ds == null || ds.Tables.Count <= || ds.Tables[].Rows.Count <= )
{
return entity;
}
return DataRowBinding(ds.Tables[].Rows[]); }
/// <summary>
/// 查询水位计的记录信息
/// </summary>
/// <param name="deviceID">设备ID</param>
/// <returns>记录信息</returns>
public IList<WaterLevelRecordInfo> GetWaterLevelRecordInfos(int deviceID)
{
string sql =
@"select t.RecordID,t.DeviceID,t.MeasuredLevel,t.RecordTime,
t.CreateBy,t.CreateTime,t.UpdateBy,t.UpdateTime,t.Remark
from dbo.WaterLevelRecord t(nolock)
where t.DeviceID=@DeviceID";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = deviceID}
};
IList<WaterLevelRecordInfo> lstWaterLevelRecordInfo = new List<WaterLevelRecordInfo>();
DataSet ds = DBHelper.ExecuteDataset(sql, paras.ToArray()); if (ds == null || ds.Tables.Count <= )
return lstWaterLevelRecordInfo;
foreach (DataRow dr in ds.Tables[].Rows)
{
WaterLevelRecordInfo entity = DataRowBinding(dr);
if (entity != null)
{
lstWaterLevelRecordInfo.Add(entity);
}
}
return lstWaterLevelRecordInfo;
}
/// <summary>
/// 分时间查出水位计相应记录信息
/// </summary>
/// <param name="deviceID">设备ID</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns>记录信息</returns>
public IList<WaterLevelRecordInfo> GetWaterLevelRecordInfos(int deviceID, DateTime startTime, DateTime endTime)
{
string sql =
@"select t.RecordID,t.DeviceID,t.MeasuredLevel,t.RecordTime,
t.CreateBy,t.CreateTime,t.Remark
from dbo.WaterLevelRecord t(nolock)
where t.DeviceID=@DeviceID and RecordTime between @startTime and @endTime";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = deviceID},
new SqlParameter("@startTime",SqlDbType.DateTime){Value = startTime },
new SqlParameter("@endTime",SqlDbType.DateTime){Value = endTime }
};
IList<WaterLevelRecordInfo> lstWaterLevelRecordInfos = new List<WaterLevelRecordInfo>();
DataSet ds = DBHelper.ExecuteDataset(sql, paras.ToArray());
if (ds == null || ds.Tables.Count <= )
{
return lstWaterLevelRecordInfos;
}
foreach (DataRow dr in ds.Tables[].Rows)
{
WaterLevelRecordInfo entity = DataRowBinding(dr);
if (entity != null)
{
lstWaterLevelRecordInfos.Add(entity);
}
}
return lstWaterLevelRecordInfos;
}
/// <summary>
/// 增加水位计记录信息
/// </summary>
/// <param name="recordInfo">水位计记录信息</param>
/// <returns>操作记录</returns>
public int AddWaterLevelRecordInfo(WaterLevelRecordInfo recordInfo)
{
if (recordInfo == null)
{
return ;
}
string sql =
@"INSERT INTO dbo.WaterLevelRecord
(DeviceID,MeasuredLevel,RecordTime,
CreateBy,CreateTime,Remark
)
VALUES
(@DeviceID,@MeasuredLevel,@RecordTime,
@CreateBy,@CreateTime,@Remark
)
SELECT @@IDENTITY";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@DeviceID",SqlDbType.Int){Value = recordInfo.DeviceID},
new SqlParameter("@MeasuredLevel",SqlDbType.Decimal){Value = recordInfo.MeasuredLevel},
new SqlParameter("@RecordTime",SqlDbType.DateTime){Value = recordInfo.RecordTime},
new SqlParameter("@CreateTime",SqlDbType.DateTime){Value = DateTime.Now},
new SqlParameter("@CreateBy",SqlDbType.NVarChar,){Value = Global.GlobalInfo.loginInfo.LoginAccount},
new SqlParameter("@Remark",SqlDbType.NChar,){Value = recordInfo.Remark},
};
object ret = DBHelper.ExecuteScalar(sql, paras.ToArray());//返回非表类查询结果,自增的ID
if (ret != null && int.Parse(ret.ToString()) >= )
{
return int.Parse(ret.ToString());
}
return ;
}
/// <summary>
/// 更新水位计记录
/// </summary>
/// <param name="recordInfo">水位计记录信息</param>
/// <returns>操作记录</returns>
public int ModifyWaterLevelRecordInfo(WaterLevelRecordInfo recordInfo)
{
if (recordInfo == null)
{
return ;
}
string sql =
@"UPDATE dbo.WaterLevelRecord
SET DeviceID=@DeviceID
,MeasuredLevel=@MeasuredLevel
,RecordTime=@RecordTime
,UpdateBy=@UpdateBy
,UpdateTime=@UpdateTime
,Remark=@Remark
WHERE RecordID=@RecordID";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@RecordID",SqlDbType.Int){Value = recordInfo.RecordID},
new SqlParameter("@DeviceID",SqlDbType.Int){Value = recordInfo.DeviceID},
new SqlParameter("@MeasuredLevel",SqlDbType.Decimal){Value = recordInfo.MeasuredLevel},
new SqlParameter("@RecordTime",SqlDbType.DateTime){Value = recordInfo.RecordTime},
new SqlParameter("@UpdateTime",SqlDbType.DateTime){Value = DateTime.Now},
new SqlParameter("@UpdateBy",SqlDbType.NVarChar,){Value = Global.GlobalInfo.loginInfo.LoginAccount},
new SqlParameter("@Remark",SqlDbType.NVarChar,){Value = recordInfo.Remark},
};
return DBHelper.ExecuteNonQuery(sql, paras.ToArray());
}
/// <summary>
/// 删除水位计记录信息
/// </summary>
/// <param name="recordInfo">水位计记录信息</param>
/// <returns>操作记录</returns>
public int DelWaterLevelRecordInfo(WaterLevelRecordInfo recordInfo)
{
if (recordInfo == null)
{
return ;
}
string sql =
@"DELETE FROM dbo.WaterLevelRecord
WHERE RecordID=@RecordID";
IList<SqlParameter> paras = new List<SqlParameter>()
{
new SqlParameter("@RecordID",SqlDbType.Int){Value = recordInfo.RecordID },
}; return DBHelper.ExecuteNonQuery(sql, paras.ToArray());
}
#region 数据绑定
private WaterLevelRecordInfo DataRowBinding(DataRow dr)
{
if (dr == null)
{
return null;
}
WaterLevelRecordInfo entity = new WaterLevelRecordInfo();
entity.DeviceID = Convert.ToInt32(dr["DeviceID"]);
entity.MeasuredLevel=Convert.ToDecimal(dr["MeasuredLevel"]);
if (dr["Remark"] != DBNull.Value)
{
entity.Remark = dr["Remark"].ToString();
}
else
{
entity.Remark = string.Empty;
}
entity.RecordTime = Convert.ToDateTime(dr["RecordTime"]);
if (dr["CreateBy"] != DBNull.Value)
{
entity.CreateBy= dr["CreateBy"].ToString();
}
else
{
entity.CreateBy = string.Empty;
}
entity.CreateTime = Convert.ToDateTime(dr["CreateTime"]);
if (dr["UpdateBy"] != DBNull.Value)
{
entity.UpdateBy = dr["UpdateBy"].ToString();
}
else
{
entity.UpdateBy = string.Empty;
}
if (dr["UpdateTime"] != DBNull.Value)
{
entity.UpdateTime = Convert.ToDateTime(dr["UpdateTime"]);
} return entity;
}
#endregion
}
}
若需转载请标明出处或链接http://www.cnblogs.com/EaIE099/,本人初入职场,对编程也是一个菜鸟,只想把自己所学点滴记录下来,如有不合理的地方希望各位高手多多指点,非常感谢!
用C#实现对MSSqlServer数据库的增删改查---DAL层的更多相关文章
- 用C#实现对MSSqlServer数据库的增删改查---Server层(WaterLevelRecordServer.cs、DeviceRecordServer.cs)
抛开现实的残酷与无奈,对技术孜孜不倦的追求,从专注到执着,从疯狂到忘我,始终坚信代码可以改变世界,更能改变自己的人生. WaterLevelRecordServer.cs using System; ...
- 用C#实现对MSSqlServer数据库的增删改查---Server层(WaterLevelSetServer.cs、DeviceSetServer.cs)
在Server层定义WaterLevelSetServer和WaterLevelRecordServer两个子类,分别继承DeviceSetServer和DeviceRecordServer. usi ...
- SQLite帮助类SQlitehelper 实现对SQLite数据的增删改查
public class SQLiteHelper { public const string sConn = "Data Source=" + @"path" ...
- python web.py操作mysql数据库,实现对数据库的增删改查操作
使用web.py框架,实现对mysql数据库的增删改查操作: 该示例代码中连接的是本地数据库testdb,user表,表结构比较简单,只有两个字段:mobile和passwd,类型均为字符型 实际应用 ...
- Java操作数据库实现"增删改查"
本文主要讲解JDBC操作数据库 主要实现对MySql数据库的"增删改查" 综合概述: JDBC的常用类和接口 一 DriverManager类 DriverManage类 ...
- ThinkPHP实现对数据库的增删改查
好久都没有更新博客了,之前老师布置的任务总算是现在可以说告一段落了,今天趁老师还没提出其他要求来更新一篇博客. 今天我想记录的是我之前做项目,自己所理解的ThinkPHP对数据库的增删改查. 首先要说 ...
- Android学习---数据库的增删改查(sqlite CRUD)
上一篇文章介绍了sqlite数据库的创建,以及数据的访问,本文将主要介绍数据库的增删改查. 下面直接看代码: MyDBHelper.java(创建数据库,添加一列phone) package com. ...
- Android 系统API实现数据库的增删改查和SQLite3工具的使用
在<Android SQL语句实现数据库的增删改查>中介绍了使用sql语句来实现数据库的增删改查操作,本文介绍Android 系统API实现数据库的增删改查和SQLite3工具的使用. 系 ...
- Android SQL语句实现数据库的增删改查
本文介绍android中的数据库的增删改查 复习sql语法: * 增 insert into info (name,phone) values ('wuyudong','111') * 删 delet ...
随机推荐
- 【Java并发编程】之二:线程中断
[Java并发编程]之二:线程中断 使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...
- Sum of Consecutive Integers LightOJ - 1278(推公式 数学思维)
原文地址:https://blog.csdn.net/qq_37632935/article/details/79465213 给你一个数n(n<=10^14),然后问n能用几个连续的数表示; ...
- elasticsearch 第三篇(安装篇)
*nux下安装 在*nux下,es官方已提供编译的deb和rpm包,但是需要保证已安装安装Java虚拟环境(目前es1.6和1.7版本均可选择1.8版本java),安装步骤如下:1.下载ES deb/ ...
- 【BZOJ3166】ALO(主席树)
[BZOJ3166]ALO(主席树) 题面 权限题qwq 资磁洛谷 题解 用一个\(set\)求出左右侧比这个数大的第\(2\)个数, 然后用可持久化\(Trie\)算一下就好啦 #include&l ...
- NOIP2017 列队 题解报告【56行线段树】
题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n \times mn×m名学生,方阵的行数 ...
- ssh后台执行
1 执行scp命令,开始传输2 scp传输开始后,用ctrl+z,再以bg命令将其转入后台运行. 3以exit命令安全退出即可令scp继续执行,不受关闭shell的影响.
- 【agc004F】Namori
Portal -->agc004F Solution 好神仙的转化qwq 首先我们可以先考虑\(m=n-1\)的情况下,也就是树的情况下要怎么做 我们可以将这个问题转化一下:我们对这颗 ...
- python基础----模块、包
一 模块 ...
- Codeforces Round #427 (Div. 2) D dp
D. Palindromic characteristics time limit per test 3 seconds memory limit per test 256 megabytes inp ...
- C++ 局部静态变量,全局变量,全局静态变量,局部变量的区别和联系
C++变量根据定义位置的不同,具有不同的作用域,作用域可分为6种:全局作用域,局部作用域,语句作用域,类作用域,命名作用域和文件作用域. 从作用域看: 全局变量具有全局作用域.全局变量只需在一个源文件 ...