zoukankan      html  css  js  c++  java
  • C#生成DBF文件

    C# 生成DBF,无需注册Microsoft.Jet.OLEDB。

     1 namespace ConsoleApplication
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             Test();
     8             Console.ReadKey();
     9         }
    10 
    11         private static void Test()
    12         {
    13             string testPath = AppDomain.CurrentDomain.BaseDirectory;
    14             var odbf = new DbfFile(Encoding.GetEncoding(936));
    15             odbf.Open(Path.Combine(testPath, "test.dbf"), FileMode.Create);
    16 
    17             //创建列头
    18             odbf.Header.AddColumn(new DbfColumn("编号", DbfColumn.DbfColumnType.Character, 20, 0));
    19             odbf.Header.AddColumn(new DbfColumn("名称", DbfColumn.DbfColumnType.Character, 20, 0));
    20             odbf.Header.AddColumn(new DbfColumn("地址", DbfColumn.DbfColumnType.Character, 20, 0));
    21             odbf.Header.AddColumn(new DbfColumn("时间", DbfColumn.DbfColumnType.Date));
    22             odbf.Header.AddColumn(new DbfColumn("余额", DbfColumn.DbfColumnType.Number, 15, 3));
    23 
    24             var orec = new DbfRecord(odbf.Header) { AllowDecimalTruncate = true };
    25             List<User> list = User.GetList();
    26             foreach (var item in list)
    27             {
    28                 orec[0] = item.UserCode;
    29                 orec[1] = item.UserName;
    30                 orec[2] = item.Address;
    31                 orec[3] = item.date.ToString("yyyy-MM-dd HH:mm:ss");
    32                 orec[4] = item.money.ToString();
    33                 odbf.Write(orec, true);
    34             }
    35             odbf.Close();
    36         }
    37     }
    38 
    39     public class User
    40     {
    41         public string UserCode { get; set; }
    42         public string UserName { get; set; }
    43         public string Address { get; set; }
    44         public DateTime date { get; set; }
    45         public decimal money { get; set; }
    46 
    47         public static List<User> GetList()
    48         {
    49             List<User> list = new List<User>();
    50             list.Add(new User() { UserCode = "A1", UserName = "张三", Address = "上海杨浦", date = DateTime.Now, money = 1000.12m });
    51             list.Add(new User() { UserCode = "A2", UserName = "李四", Address = "湖北武汉", date = DateTime.Now, money = 31000.008m });
    52             list.Add(new User() { UserCode = "A3", UserName = "王子龙", Address = "陕西西安", date = DateTime.Now, money = 2000.12m });
    53             list.Add(new User() { UserCode = "A4", UserName = "李三", Address = "北京", date = DateTime.Now, money = 3000.12m });
    54             return list;
    55         }
    56     }
    57 
    58 }

    生成的文件截图:

    操作DBF文件的部分代码:

      1 ///
      2 /// Author: Ahmed Lacevic
      3 /// Date: 12/1/2007
      4 /// Desc: 
      5 /// 
      6 /// Revision History:
      7 /// -----------------------------------
      8 ///   Author:
      9 ///   Date:
     10 ///   Desc:
     11 
     12 
     13 using System;
     14 using System.Collections.Generic;
     15 using System.Text;
     16 using System.IO;
     17 using System.Globalization;
     18 
     19 
     20 namespace SocialExplorer.IO.FastDBF
     21 {
     22 
     23     /// <summary>
     24     /// Use this class to create a record and write it to a dbf file. You can use one record object to write all records!!
     25     /// It was designed for this kind of use. You can do this by clearing the record of all data 
     26     /// (call Clear() method) or setting values to all fields again, then write to dbf file. 
     27     /// This eliminates creating and destroying objects and optimizes memory use.
     28     /// 
     29     /// Once you create a record the header can no longer be modified, since modifying the header would make a corrupt DBF file.
     30     /// </summary>
     31     public class DbfRecord
     32     {
     33 
     34         /// <summary>
     35         /// Header provides information on all field types, sizes, precision and other useful information about the DBF.
     36         /// </summary>
     37         private DbfHeader mHeader = null;
     38 
     39         /// <summary>
     40         /// Dbf data are a mix of ASCII characters and binary, which neatly fit in a byte array.
     41         /// BinaryWriter would esentially perform the same conversion using the same Encoding class.
     42         /// </summary>
     43         private byte[] mData = null;
     44 
     45         /// <summary>
     46         /// Zero based record index. -1 when not set, new records for example.
     47         /// </summary>
     48         private int mRecordIndex = -1;
     49 
     50         /// <summary>
     51         /// Empty Record array reference used to clear fields quickly (or entire record).
     52         /// </summary>
     53         private readonly byte[] mEmptyRecord = null;
     54 
     55 
     56         /// <summary>
     57         /// Specifies whether we allow strings to be truncated. If false and string is longer than we can fit in the field, an exception is thrown.
     58         /// </summary>
     59         private bool mAllowStringTruncate = true;
     60 
     61         /// <summary>
     62         /// Specifies whether we allow the decimal portion of numbers to be truncated. 
     63         /// If false and decimal digits overflow the field, an exception is thrown.
     64         /// </summary>
     65         private bool mAllowDecimalTruncate = false;
     66 
     67         /// <summary>
     68         /// Specifies whether we allow the integer portion of numbers to be truncated.
     69         /// If false and integer digits overflow the field, an exception is thrown.
     70         /// </summary>
     71         private bool mAllowIntegerTruncate = false;
     72 
     73 
     74         //array used to clear decimals, we can clear up to 40 decimals which is much more than is allowed under DBF spec anyway.
     75         //Note: 48 is ASCII code for 0.
     76         private static readonly byte[] mDecimalClear = new byte[] {48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
     77                                                                48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
     78                                                                48,48,48,48,48,48,48,48,48,48,48,48,48,48,48};
     79 
     80 
     81         //Warning: do not make this one static because that would not be thread safe!! The reason I have 
     82         //placed this here is to skip small memory allocation/deallocation which fragments memory in .net.
     83         private int[] mTempIntVal = { 0 };
     84 
     85 
     86         //Ascii Encoder
     87         private readonly Encoding encoding = Encoding.ASCII;
     88 
     89         /// <summary>
     90         /// Column Name to Column Index map
     91         /// </summary>
     92         private readonly Dictionary<string, int> mColNameToConIdx = new Dictionary<string, int>(StringComparer.InvariantCulture);
     93 
     94 
     95 
     96         /// <summary>
     97         /// 
     98         /// </summary>
     99         /// <param name="oHeader">Dbf Header will be locked once a record is created 
    100         /// since the record size is fixed and if the header was modified it would corrupt the DBF file.</param>
    101         public DbfRecord(DbfHeader oHeader)
    102         {
    103             mHeader = oHeader;
    104             mHeader.Locked = true;
    105 
    106             //create a buffer to hold all record data. We will reuse this buffer to write all data to the file.
    107             mData = new byte[mHeader.RecordLength];
    108             mEmptyRecord = mHeader.EmptyDataRecord;
    109             encoding = oHeader.encoding;
    110 
    111             for (int i = 0; i < oHeader.mFields.Count; i++)
    112                 mColNameToConIdx[oHeader.mFields[i].Name] = i;
    113         }
    114 
    115 
    116         /// <summary>
    117         /// Set string data to a column, if the string is longer than specified column length it will be truncated!
    118         /// If dbf column type is not a string, input will be treated as dbf column 
    119         /// type and if longer than length an exception will be thrown.
    120         /// </summary>
    121         /// <param name="nColIndex"></param>
    122         /// <returns></returns>
    123         public string this[int nColIndex]
    124         {
    125 
    126             set
    127             {
    128 
    129                 DbfColumn ocol = mHeader[nColIndex];
    130                 DbfColumn.DbfColumnType ocolType = ocol.ColumnType;
    131 
    132 
    133                 //
    134                 //if an empty value is passed, we just clear the data, and leave it blank.
    135                 //note: test have shown that testing for null and checking length is faster than comparing to "" empty str :)
    136                 //------------------------------------------------------------------------------------------------------------
    137                 if (string.IsNullOrEmpty(value))
    138                 {
    139                     //this is like NULL data, set it to empty. i looked at SAS DBF output when a null value exists 
    140                     //and empty data are output. we get the same result, so this looks good.
    141                     Buffer.BlockCopy(mEmptyRecord, ocol.DataAddress, mData, ocol.DataAddress, ocol.Length);
    142 
    143                 }
    144                 else
    145                 {
    146 
    147                     //set values according to data type:
    148                     //-------------------------------------------------------------
    149                     if (ocolType == DbfColumn.DbfColumnType.Character)
    150                     {
    151                         if (!mAllowStringTruncate && value.Length > ocol.Length)
    152                             throw new DbfDataTruncateException("Value not set. String truncation would occur and AllowStringTruncate flag is set to false. To supress this exception change AllowStringTruncate to true.");
    153 
    154                         //BlockCopy copies bytes.  First clear the previous value, then set the new one.
    155                         Buffer.BlockCopy(mEmptyRecord, ocol.DataAddress, mData, ocol.DataAddress, ocol.Length);
    156                         encoding.GetBytes(value, 0, value.Length > ocol.Length ? ocol.Length : value.Length, mData, ocol.DataAddress);
    157 
    158                     }
    159                     else if (ocolType == DbfColumn.DbfColumnType.Number)
    160                     {
    161 
    162                         if (ocol.DecimalCount == 0)
    163                         {
    164 
    165                             //integers
    166                             //----------------------------------
    167 
    168                             //throw an exception if integer overflow would occur
    169                             if (!mAllowIntegerTruncate && value.Length > ocol.Length)
    170                                 throw new DbfDataTruncateException("Value not set. Integer does not fit and would be truncated. AllowIntegerTruncate is set to false. To supress this exception set AllowIntegerTruncate to true, although that is not recomended.");
    171 
    172 
    173                             //clear all numbers, set to [space].
    174                             //-----------------------------------------------------
    175                             Buffer.BlockCopy(mEmptyRecord, 0, mData, ocol.DataAddress, ocol.Length);
    176 
    177 
    178                             //set integer part, CAREFUL not to overflow buffer! (truncate instead)
    179                             //-----------------------------------------------------------------------
    180                             int nNumLen = value.Length > ocol.Length ? ocol.Length : value.Length;
    181                             encoding.GetBytes(value, 0, nNumLen, mData, (ocol.DataAddress + ocol.Length - nNumLen));
    182 
    183                         }
    184                         else
    185                         {
    186 
    187                             ///TODO: we can improve perfomance here by not using temp char arrays cDec and cNum,
    188                             ///simply direcly copy from source string using encoding!
    189 
    190 
    191                             //break value down into integer and decimal portions
    192                             //--------------------------------------------------------------------------
    193                             int nidxDecimal = value.IndexOf('.'); //index where the decimal point occurs
    194                             char[] cDec = null; //decimal portion of the number
    195                             char[] cNum = null; //integer portion
    196 
    197                             if (nidxDecimal > -1)
    198                             {
    199                                 cDec = value.Substring(nidxDecimal + 1).Trim().ToCharArray();
    200                                 cNum = value.Substring(0, nidxDecimal).ToCharArray();
    201 
    202                                 //throw an exception if decimal overflow would occur
    203                                 if (!mAllowDecimalTruncate && cDec.Length > ocol.DecimalCount)
    204                                     throw new DbfDataTruncateException("Value not set. Decimal does not fit and would be truncated. AllowDecimalTruncate is set to false. To supress this exception set AllowDecimalTruncate to true.");
    205 
    206                             }
    207                             else
    208                                 cNum = value.ToCharArray();
    209 
    210 
    211                             //throw an exception if integer overflow would occur
    212                             if (!mAllowIntegerTruncate && cNum.Length > ocol.Length - ocol.DecimalCount - 1)
    213                                 throw new DbfDataTruncateException("Value not set. Integer does not fit and would be truncated. AllowIntegerTruncate is set to false. To supress this exception set AllowIntegerTruncate to true, although that is not recomended.");
    214 
    215 
    216 
    217                             //clear all decimals, set to 0.
    218                             //-----------------------------------------------------
    219                             Buffer.BlockCopy(mDecimalClear, 0, mData, (ocol.DataAddress + ocol.Length - ocol.DecimalCount), ocol.DecimalCount);
    220 
    221                             //clear all numbers, set to [space].
    222                             Buffer.BlockCopy(mEmptyRecord, 0, mData, ocol.DataAddress, (ocol.Length - ocol.DecimalCount));
    223 
    224 
    225 
    226                             //set decimal numbers, CAREFUL not to overflow buffer! (truncate instead)
    227                             //-----------------------------------------------------------------------
    228                             if (nidxDecimal > -1)
    229                             {
    230                                 int nLen = cDec.Length > ocol.DecimalCount ? ocol.DecimalCount : cDec.Length;
    231                                 encoding.GetBytes(cDec, 0, nLen, mData, (ocol.DataAddress + ocol.Length - ocol.DecimalCount));
    232                             }
    233 
    234                             //set integer part, CAREFUL not to overflow buffer! (truncate instead)
    235                             //-----------------------------------------------------------------------
    236                             int nNumLen = cNum.Length > ocol.Length - ocol.DecimalCount - 1 ? (ocol.Length - ocol.DecimalCount - 1) : cNum.Length;
    237                             encoding.GetBytes(cNum, 0, nNumLen, mData, ocol.DataAddress + ocol.Length - ocol.DecimalCount - nNumLen - 1);
    238 
    239 
    240                             //set decimal point
    241                             //-----------------------------------------------------------------------
    242                             mData[ocol.DataAddress + ocol.Length - ocol.DecimalCount - 1] = (byte)'.';
    243 
    244 
    245                         }
    246 
    247 
    248                     }
    249                     else if (ocolType == DbfColumn.DbfColumnType.Integer)
    250                     {
    251                         //note this is a binary Integer type!
    252                         //----------------------------------------------
    253 
    254                         ///TODO: maybe there is a better way to copy 4 bytes from int to byte array. Some memory function or something.
    255                         mTempIntVal[0] = Convert.ToInt32(value);
    256                         Buffer.BlockCopy(mTempIntVal, 0, mData, ocol.DataAddress, 4);
    257 
    258                     }
    259                     else if (ocolType == DbfColumn.DbfColumnType.Memo)
    260                     {
    261                         //copy 10 digits...
    262                         ///TODO: implement MEMO
    263 
    264                         throw new NotImplementedException("Memo data type functionality not implemented yet!");
    265 
    266                     }
    267                     else if (ocolType == DbfColumn.DbfColumnType.Boolean)
    268                     {
    269                         if (String.Compare(value, "true", true) == 0 || String.Compare(value, "1", true) == 0 ||
    270                             String.Compare(value, "T", true) == 0 || String.Compare(value, "yes", true) == 0 ||
    271                             String.Compare(value, "Y", true) == 0)
    272                             mData[ocol.DataAddress] = (byte)'T';
    273                         else if (value == " " || value == "?")
    274                             mData[ocol.DataAddress] = (byte)'?';
    275                         else
    276                             mData[ocol.DataAddress] = (byte)'F';
    277 
    278                     }
    279                     else if (ocolType == DbfColumn.DbfColumnType.Date)
    280                     {
    281                         //try to parse out date value using Date.Parse() function, then set the value
    282                         DateTime dateval;
    283                         if (DateTime.TryParse(value, out dateval))
    284                         {
    285                             SetDateValue(nColIndex, dateval);
    286                         }
    287                         else
    288                             throw new InvalidOperationException("Date could not be parsed from source string! Please parse the Date and set the value (you can try using DateTime.Parse() or DateTime.TryParse() functions).");
    289 
    290                     }
    291                     else if (ocolType == DbfColumn.DbfColumnType.Binary)
    292                         throw new InvalidOperationException("Can not use string source to set binary data. Use SetBinaryValue() and GetBinaryValue() functions instead.");
    293 
    294                     else
    295                         throw new InvalidDataException("Unrecognized data type: " + ocolType.ToString());
    296 
    297                 }
    298 
    299             }
    300 
    301             get
    302             {
    303                 DbfColumn ocol = mHeader[nColIndex];
    304                 return new string(encoding.GetChars(mData, ocol.DataAddress, ocol.Length));
    305 
    306             }
    307         }
    308 
    309         /// <summary>
    310         /// Set string data to a column, if the string is longer than specified column length it will be truncated!
    311         /// If dbf column type is not a string, input will be treated as dbf column 
    312         /// type and if longer than length an exception will be thrown.
    313         /// </summary>
    314         /// <param name="nColName"></param>
    315         /// <returns></returns>
    316         public string this[string nColName]
    317         {
    318             get
    319             {
    320                 if (mColNameToConIdx.ContainsKey(nColName))
    321                     return this[mColNameToConIdx[nColName]];
    322                 throw new InvalidOperationException(string.Format("There's no column with name '{0}'", nColName));
    323             }
    324             set
    325             {
    326                 if (mColNameToConIdx.ContainsKey(nColName))
    327                     this[mColNameToConIdx[nColName]] = value;
    328                 else
    329                     throw new InvalidOperationException(string.Format("There's no column with name '{0}'", nColName));
    330             }
    331         }
    332 
    333         /// <summary>
    334         /// Get date value.
    335         /// </summary>
    336         /// <param name="nColIndex"></param>
    337         /// <returns></returns>
    338         public DateTime GetDateValue(int nColIndex)
    339         {
    340             DbfColumn ocol = mHeader[nColIndex];
    341 
    342             if (ocol.ColumnType == DbfColumn.DbfColumnType.Date)
    343             {
    344                 string sDateVal = encoding.GetString(mData, ocol.DataAddress, ocol.Length);
    345                 return DateTime.ParseExact(sDateVal, "yyyyMMdd", CultureInfo.InvariantCulture);
    346 
    347             }
    348             else
    349                 throw new Exception("Invalid data type. Column '" + ocol.Name + "' is not a date column.");
    350 
    351         }
    352 
    353 
    354         /// <summary>
    355         /// Get date value.
    356         /// </summary>
    357         /// <param name="nColIndex"></param>
    358         /// <returns></returns>
    359         public void SetDateValue(int nColIndex, DateTime value)
    360         {
    361 
    362             DbfColumn ocol = mHeader[nColIndex];
    363             DbfColumn.DbfColumnType ocolType = ocol.ColumnType;
    364 
    365 
    366             if (ocolType == DbfColumn.DbfColumnType.Date)
    367             {
    368 
    369                 //Format date and set value, date format is like this: yyyyMMdd
    370                 //-------------------------------------------------------------
    371                 encoding.GetBytes(value.ToString("yyyyMMdd"), 0, ocol.Length, mData, ocol.DataAddress);
    372 
    373             }
    374             else
    375                 throw new Exception("Invalid data type. Column is of '" + ocol.ColumnType.ToString() + "' type, not date.");
    376 
    377 
    378         }
    379 
    380 
    381         /// <summary>
    382         /// Clears all data in the record.
    383         /// </summary>
    384         public void Clear()
    385         {
    386             Buffer.BlockCopy(mEmptyRecord, 0, mData, 0, mEmptyRecord.Length);
    387             mRecordIndex = -1;
    388 
    389         }
    390 
    391 
    392         /// <summary>
    393         /// returns a string representation of this record.
    394         /// </summary>
    395         /// <returns></returns>
    396         public override string ToString()
    397         {
    398             return new string(encoding.GetChars(mData));
    399         }
    400 
    401 
    402         /// <summary>
    403         /// Gets/sets a zero based record index. This information is not directly stored in DBF. 
    404         /// It is the location of this record within the DBF. 
    405         /// </summary>
    406         /// <remarks>
    407         /// This property is managed from outside this object,
    408         /// CDbfFile object updates it when records are read. The reason we don't set it in the Read() 
    409         /// function within this object is that the stream can be forward-only so the Position property 
    410         /// is not available and there is no way to figure out what index the record was unless you 
    411         /// count how many records were read, and that's exactly what CDbfFile does.
    412         /// </remarks>
    413         public int RecordIndex
    414         {
    415             get
    416             {
    417                 return mRecordIndex;
    418             }
    419             set
    420             {
    421                 mRecordIndex = value;
    422             }
    423         }
    424 
    425 
    426         /// <summary>
    427         /// Returns/sets flag indicating whether this record was tagged deleted. 
    428         /// </summary>
    429         /// <remarks>Use CDbf4File.Compress() function to rewrite dbf removing records flagged as deleted.</remarks>
    430         /// <seealso cref="CDbf4File.Compress() function"/>
    431         public bool IsDeleted
    432         {
    433             get { return mData[0] == '*'; }
    434             set { mData[0] = value ? (byte)'*' : (byte)' '; }
    435         }
    436 
    437 
    438         /// <summary>
    439         /// Specifies whether strings can be truncated. If false and string is longer than can fit in the field, an exception is thrown.
    440         /// Default is True.
    441         /// </summary>
    442         public bool AllowStringTurncate
    443         {
    444             get { return mAllowStringTruncate; }
    445             set { mAllowStringTruncate = value; }
    446         }
    447 
    448         /// <summary>
    449         /// Specifies whether to allow the decimal portion of numbers to be truncated. 
    450         /// If false and decimal digits overflow the field, an exception is thrown. Default is false.
    451         /// </summary>
    452         public bool AllowDecimalTruncate
    453         {
    454             get { return mAllowDecimalTruncate; }
    455             set { mAllowDecimalTruncate = value; }
    456         }
    457 
    458 
    459         /// <summary>
    460         /// Specifies whether integer portion of numbers can be truncated.
    461         /// If false and integer digits overflow the field, an exception is thrown. 
    462         /// Default is False.
    463         /// </summary>
    464         public bool AllowIntegerTruncate
    465         {
    466             get { return mAllowIntegerTruncate; }
    467             set { mAllowIntegerTruncate = value; }
    468         }
    469 
    470 
    471         /// <summary>
    472         /// Returns header object associated with this record.
    473         /// </summary>
    474         public DbfHeader Header
    475         {
    476             get
    477             {
    478                 return mHeader;
    479             }
    480         }
    481 
    482 
    483         /// <summary>
    484         /// Get column by index.
    485         /// </summary>
    486         /// <param name="index"></param>
    487         /// <returns></returns>
    488         public DbfColumn Column(int index)
    489         {
    490             return mHeader[index];
    491         }
    492 
    493         /// <summary>
    494         /// Get column by name.
    495         /// </summary>
    496         /// <param name="index"></param>
    497         /// <returns></returns>
    498         public DbfColumn Column(string sName)
    499         {
    500             return mHeader[sName];
    501         }
    502 
    503         /// <summary>
    504         /// Gets column count from header.
    505         /// </summary>
    506         public int ColumnCount
    507         {
    508             get
    509             {
    510                 return mHeader.ColumnCount;
    511             }
    512         }
    513 
    514         /// <summary>
    515         /// Finds a column index by searching sequentially through the list. Case is ignored. Returns -1 if not found.
    516         /// </summary>
    517         /// <param name="sName">Column name.</param>
    518         /// <returns>Column index (0 based) or -1 if not found.</returns>
    519         public int FindColumn(string sName)
    520         {
    521             return mHeader.FindColumn(sName);
    522         }
    523 
    524         /// <summary>
    525         /// Writes data to stream. Make sure stream is positioned correctly because we simply write out the data to it.
    526         /// </summary>
    527         /// <param name="osw"></param>
    528         protected internal void Write(Stream osw)
    529         {
    530             osw.Write(mData, 0, mData.Length);
    531 
    532         }
    533 
    534 
    535         /// <summary>
    536         /// Writes data to stream. Make sure stream is positioned correctly because we simply write out data to it, and clear the record.
    537         /// </summary>
    538         /// <param name="osw"></param>
    539         protected internal void Write(Stream obw, bool bClearRecordAfterWrite)
    540         {
    541             obw.Write(mData, 0, mData.Length);
    542 
    543             if (bClearRecordAfterWrite)
    544                 Clear();
    545 
    546         }
    547 
    548 
    549         /// <summary>
    550         /// Read record from stream. Returns true if record read completely, otherwise returns false.
    551         /// </summary>
    552         /// <param name="obr"></param>
    553         /// <returns></returns>
    554         protected internal bool Read(Stream obr)
    555         {
    556             return obr.Read(mData, 0, mData.Length) >= mData.Length;
    557         }
    558 
    559         protected internal string ReadValue(Stream obr, int colIndex)
    560         {
    561             DbfColumn ocol = mHeader[colIndex];
    562             return new string(encoding.GetChars(mData, ocol.DataAddress, ocol.Length));
    563 
    564         }
    565 
    566     }
    567 }
    View Code

    完整代码下载(含FastDBF源代码):下载

  • 相关阅读:
    令人抓狂的redis和rediscluster Python驱动包的安装
    基于Docker的Consul集群实现服务发现
    应用中引入缓存层后,缓存和持久化层数据一致性的思考
    Redis中几个简单的概念:缓存穿透/击穿/雪崩,别再被吓唬了
    Redis Cluster 自动化安装,扩容和缩容
    mysql 8.0 忘记root密码后重置
    MySQL 8.0部分弃用的参数整理
    MySQL Online DDL与DML并发阻塞关系总结
    MySQL Error Log 文件丢失导致The server quit without updating PID file启动失败的场景
    MySQL删除大表时潜在的问题(drop table,truncate table)
  • 原文地址:https://www.cnblogs.com/wz122889488/p/4687906.html
Copyright © 2011-2022 走看看