如何使用T-SQL备份还原数据库及c#如何调用执行?
准备材料:Microsoft SQL Server一部、需要还原的bak文件一只
一、备份
数据库备份语句:user master backup database 数据库名 to disk='保存路径\dbName.bak'
实战操作:这里要使用sql语句对TEST数据库进行备份,当然你也可以使用mssql自带工具进行操作,咦,麻烦死了
一句sql:
use master backup database TEST to disk='C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\TEST.bak'
截图童叟无欺:
二、还原 相对较为麻烦,因为有日志文件的问题还有杀死连接的问题。
数据库还原语句:
use master restore database 数据库名 from disk='保存路径\dbName.bak' WITH MOVE 'dbName_Data' to '保存路径\test20160428.mdf',
move 'dbName_Log' to '保存路径\test20160428_Log.mdf'
实战操作:这里我重新找了一个bak文件进行还原。源Bak文件名:FTZMIS20151218.bak
①首先,首先要查找到源bak文件中的数据文件和日志文件名称,需要一条SQL语句
sql:
restore filelistonly from disk = 'F:\华美数据核对20160407\FTZMIS20151218.bak'---查找BAK文件相关信息
结果:LogicalName列下的值就分别问数据文件名称和日志文件名称,待会要用到。
②正题开始,进行还原操作。
sql:
restore database kaifang from disk = 'F:\华美数据核对20160407\FTZMIS20151218.bak'--源bak文件 with REPLACE--这句的意思是是否覆盖目标数据,也就是这里的数据库:kaifang , move 'ABOQDB' to 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\FTZMIS.mdf'--数据文件还原后存放的新位置 ,move 'ABOQDB_log' to 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\FTZMIS_1.ldf'--日志文件还原后存放的新位置
截图:暂无,还原还在执行
截图来了,
C#中索引器的作用和实现。
官方描述:索引器允许类或结构的实例就像数组一样进行索引。索引器形态类似于,不同之处在于它们的取值函数采用参数。
这一功能在创建集合类的场合特别有用,而在其他某些情况下,比如处理大型文件或者抽象有些资源等,能让类具有类似数组行为也是非常有用的。
大致结构:
<modifier><return type> this [argument list]
{
get{//读}
set{//写}
}
其中:
modifier:修饰符,如:public,private,protected
this:是C#中一个特殊的关键字,表示引用类的当前实例。这里是当前类的索引。
argument list:这里是索引器的参数
一个简单例子,通过索引器返回一个字符串:
class Sample { public string this [int index] { get {return "当前索引号为:" + index; } } } Sample s=new Sample(); Console.WriteLine(s[23]); //结果 //当前索引号为:23
技巧:
1.在定义索引器的时候,不一定只采用一个参数,同一类中还可以拥有一个以上的索引器,也就是重载。
2.索引器的参数可以采用任何类型,不过int是最为合理的类型。
属性和索引器差别:
1.类的每一个属性都必须拥有唯一的名称,而类里定义的每一个索引器都必须拥有唯一的签名(signature)或者参数列表(这样就可以实现索引器重载)。
2.属性可以是static(静态的)而索引器则必须是实例成员。
3.为索引器定义的访问函数可以访问传递给索引器的参数,而属性访问函数则没有参数。
接口(interface):
类似数组的行为常受到程序实现者的喜爱,所以你还可以为接口定义索引器,IList和 IDictionary集合接口都声明了索引器以便访问其存储的项目。 在为接口声明索引器的时候,记住声明只是表示索引器的存在。你只需要提供恰当的访问函数即可,不必包括范围修饰符。以下代码把索引器声明为接口IImplementMe的一部分:
interface IImplementMe { string this[int index] { get; set; }
相应实现的类则必须为IimplementMe的索引器具体定义get和set访问函数。
官方代码实例:
class SampleCollection<T> { // Declare an array to store the data elements. private T[] arr = new T[100]; // Define the indexer, which will allow client code // to use [] notation on the class instance itself. // (See line 2 of code in Main below.) public T this[int i] { get { // This indexer is very simple, and just returns or sets // the corresponding element from the internal array. return arr[i]; } set { arr[i] = value; } } } // This class shows how client code uses the indexer. class Program { static void Main(string[] args) { // Declare an instance of the SampleCollection type. SampleCollection<string> stringCollection = new SampleCollection<string>(); // Use [] notation on the type. stringCollection[0] = "Hello, World"; System.Console.WriteLine(stringCollection[0]); } } // Output: // Hello, World.
码友实例:
非常实用
namespace Study { class Program { static void Main(string[] args) { ScoreIndex s = new ScoreIndex(); s["张三", 1] = 90; s["张三", 2] = 100; s["张三", 3] = 80; s["李四", 1] = 60; s["李四", 2] = 70; s["李四", 3] = 50; Console.WriteLine("张三课程编号为1的成绩为:" + s["张三",1]); Console.WriteLine("张三的所有成绩为:"); ArrayList temp; temp = s["张三"]; foreach (IndexClass b in temp) { Console.WriteLine("姓名:" + b.Name + "课程编号:" + b.CourseID + "分数:" + b.Score); } Console.ReadKey(); } } class IndexClass { private string _name; private int _courseid; private int _score; public IndexClass(string _name, int _courseid, int _score) { this._name = _name; this._courseid = _courseid; this._score = _score; } public string Name { get { return _name; } set { this._name = value; } } public int CourseID { get { return _courseid; } set { this._courseid = value; } } public int Score { get { return _score; } set { this._score = value; } } } class ScoreIndex { private ArrayList arr; public ScoreIndex() { arr = new ArrayList(); } public int this[string _name, int _courseid] { get { foreach (IndexClass a in arr) { if (a.Name == _name && a.CourseID == _courseid) { return a.Score; } } return -1; } set { arr.Add(new IndexClass(_name, _courseid, value)); //arr["张三",1]=90 } } //重载索引器 public ArrayList this[string _name] { get { ArrayList temp = new ArrayList(); foreach (IndexClass b in arr) { if (b.Name == _name) { temp.Add(b); } } return temp; } } } }
jquery控制元素的隐藏和显示的几种方法。
组织略显凌乱,请耐心看!
使用jquery控制div的显示与隐藏,一句话就能搞定,例如:
1.$("#id").show()表示为display:block,
$("#id").hide()表示为display:none;
2.$("#id").toggle()切换元素的可见状态。如果元素是可见的,切换为隐藏的;如果元素是隐藏的,则切换为可见的。
3.$("#id").css('display','none');//隐藏
$("#id").css('display','block');//显示
或者
$("#id")[0].style.display='none';
display=none 控制对象的隐藏
display=block控制对象的显示
4.$("#id").css('visibility','hidden');//元素隐藏
$("#id").css('visibility','visible');//元素显示
CSS visibility 属性规定元素是否可见。
visible 元素可见。
hidden 元素不可见。
collapse 在表格元素中使用时,此值可删除一行或一列,但它不影响表格的布局。被行或列占据的空间会留给其他内容使用。如果此值被用在其他的元素上,会呈现为 "hidden"。
inherit 从父元素继承 visibility 属性的值。
注意:
display:none和visible:hidden都能把网页上某个元素隐藏起来,在视觉效果上没有区别,但是在一些DOM操作中两者有区别:
display:none ---不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就是看不见也摸不到。
visible:hidden--- 使对象在网页上不可见,但该对象在网页上所占的空间没有改变,即它仍然具有高度、宽度等属性,通俗来说就是看不见但摸得到。
//第1种方法 ,给元素设置style属性 $("#hidediv").css("display", "block"); //第2种方法 ,给元素换class,来实现隐藏div,前提是换的class样式定义好了隐藏属性 $("#hidediv").attr("class", "blockclass"); //第3种方法,通过jquery的css方法,设置div隐藏 $("#blockdiv").css("display", "none"); $("#hidediv").show();//显示div $("#blockdiv").hide();//隐藏div
localStorage和sessionStorage一样都是用来存储客户端临时信息的对象。
他们均只能存储字符串类型的对象(虽然规范中可以存储其他原生类型的对象,但是目前为止没有浏览器对其进行实现)。
-
localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。
sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就被清空了。
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标签页仅指*窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。
-
同源的判断规则:
http://www.test.com
https://www.test.com (不同源,因为协议不同)
http://my.test.com(不同源,因为主机名不同)
http://www.test.com:8080(不同源,因为端口不同)
-
localStorage和sessionStorage使用时使用相同的API:
localStorage.setItem("key","value");//以“key”为名称存储一个值“value”
localStorage.getItem("key");//获取名称为“key”的值
枚举localStorage的方法:
for(var i=0;i<localStorage.length;i++){
var name = localStorage.key(i);
var value = localStorage.getItem(name);
}
删除localStorage中存储信息的方法:
localStorage.removeItem("key");//删除名称为“key”的信息。
localStorage.clear();//清空localStorage中所有信息
-
通过getItem或直接使用localStorage["key"]获取到的信息均为实际存储的副本。
例如:
localStorage.key = {value1:"value1"};
localStorage.key.value1='a';
这里是无法对实际存储的值产生作用的,下面的写法也不可以:
localStorage.getItem("key").value1="a";
当创建AspNetCore项目时
当我们创建一个AspNetCore项目时,需要我们手动添加Log:
services.AddLoging();
我们发现,Log在微软原生的包Microsoft.Extensions.Logging、Microsoft.Extensions.Logging.Configuration内。并且创建ASPNetCore项目时,NetCore SDK已经包括了这两个Log的原生包。
使用类库
目前本人在微软原生日志类库的基础之上,写了一个Log的扩展。目的是为了更好地扩展Log。当我们需要自定义自己的Log记录方式时,使用此库是你的明智选择。
类库地址信息
Nuget地址:https://www.nuget.org/packages/Alun.AspNetCore.Log.Extensions
GitHub开源地址:https://github.com/cjt321/Alun.AspNetCore.Log.Extensions
怎么使用此类库?
首先,引用Nuget包的地址。在项目启动时,添加Log的配置。
services.AddLogging(cfg => { cfg.AddNvLog(new LogConfiguration(){UseTraceLog = false, UseDebugLog = true, UseInformationLog = true, UseErrorLog = true, UseCriticalLog = true}) .AddDefaultWriteLog(); });
在AddNvLog方法中,Log级别可配置:UseTraceLog、UseDebugLog、UseInformationLog、UseErrorLog、UseCriticalLog。 如果为true,则执行相应的Log。
那么什么时候记录Log呢?
很简单,就像我们平时在NetCore中记录Log一样即可,无任何修改。可在源码WebApplicationDemo中看到记录Log。
扩展类库
当我们需要扩展日志以自己的逻辑记录到文件、队列、MySql、Mongodb等持久化时,可以扩展类库,扩展也很简单。
对于mongodb扩展类库,nuget上也有个包,但是此包只能满足一般的需求,对于复杂的需求还不能满足,需要用户自己扩展自己的逻辑。
以Alun.AspNetCore.Log.Extensions.MongoDb为例
此包是对Log保存在Mongodb中。
此包在Nuget:https://www.nuget.org/packages/Alun.AspNetCore.Log.Extensions.MongoDb
1)安装Alun.AspNetCore.Log.Extensions的nuget,因为这里需要用到mongodb,所以安装MongoDB.Driver。
2)添加mongodb的writelog类,来继承IWriteLog。
注意,我们在WriteLog方法中写日志,记录到mongodb中,此方法实现的是我们需要自定义的逻辑。这里把日志通过实体方法,持久化。
为何要继承IWriteLog?因为我们需要用到自己的逻辑,继承此类为了使用DI/IOC时,可以直接注入继承IWriteLog的类。
众所周知,使用DI/IOC时。有一好处,所有的对象都存放在容器上,如果需要修改容器里面对象,则可以通过注入的方式修改。对于继承,我们可以注入接口与实现类的方式,灵活变更实现类。
所以,我们需要在容器上初始化IWriteLog与MongoDbWriteLog的关系。
3)添加扩展配置
我们主要看初始化mongodb的writelog配置,这里在容器中注入了IWriteLog, MongoDbWriteLog的继承关系。
如何使用?
很简单,可查看WebApplicationDemo.MongoDb中,加入Mongdb的配置即可:
扩展类库的原理
使用依赖注入,注入我们需要的Log逻辑类,如Mongdb中的MongoDbWriteLog。所以,需要扩展,只需要继承IWriteLog,并且注入,就能扩展类了,很方便。
总结
读了本编文章的上部分时,慢慢会发现,使用Log扩展,就行完积木游戏一样,你想怎么‘组合’、怎么‘拆’都可以。如果你想把Log保存在队列,即实现IWriteLog,并且注入到容器中即可。如果你想把Log保存在Mongodb,一样的逻辑。所以,任意地组合,很方便。
以上,都是Net Core正在发展的方向:低耦合、高内聚。在Log中提现了。并且默认自带了依赖注入,依赖注入的好处有很多,可查看本人的依赖注入文章系列。
span<T>之高性能字符串操作实测
.net中的字符串操作性能问题由来已久,幸运的是微软推出了span<T>高性能指针操作封装工具类。这个类到底有多高的性能呢?网上传言反正很高,但是实际上在网上很难找到合适的测试实例,这让本人实在无力吐槽。经不住高性能这三个字的诱惑,本人还是了解了一番后做了几个简单样例来测试一番,下面列出几种字符串常见操作的测试代码及其运行结果。
一、String.Index 测试
1 var t1 = StopWacherHelper.DoTimer(() => 2 { 3 for (int i = 0; i < count; i++) 4 { 5 str.IndexOf(subStr); 6 } 7 }); 8 9 Console.WriteLine($"string.IndexOf {count} 次用时:{t1} 毫秒");
1 var t2 = StopWacherHelper.DoTimer(() => 2 { 3 var strSpan = str.AsSpan(); 4 5 var subStrSpan = subStr.AsSpan(); 6 7 for (int i = 0; i < count; i++) 8 { 9 strSpan.IndexOf(subStrSpan); 10 } 11 }); 12 13 Console.WriteLine($"Span<T>.IndexOf {count} 次用时:{t2} 毫秒");
二、String.Substring 测试
1 var t1 = StopWacherHelper.DoTimer(() => 2 { 3 for (int i = 0; i < count; i++) 4 { 5 str.Substring(0, str.IndexOf(subStr)); 6 } 7 }); 8 9 Console.WriteLine($"String.Substring {count} 次用时:{t1} 毫秒");
1 var t2 = StopWacherHelper.DoTimer(() => 2 { 3 var strSpan = str.AsSpan(); 4 5 var subStrSpan = subStr.AsSpan(); 6 7 var index = strSpan.IndexOf(subStrSpan); 8 9 for (int i = 0; i < count; i++) 10 { 11 strSpan.Slice(0, strSpan.IndexOf(subStrSpan)); 12 } 13 });
三、String.Split 测试
1 var t1 = StopWacherHelper.DoTimer(() => 2 { 3 for (int i = 0; i < count; i++) 4 { 5 var arr = str.Split(new string[] { splitStr }, StringSplitOptions.None); 6 } 7 }); 8 9 Console.WriteLine($"String.Split {count} 次用时:{t1} 毫秒");
1 var t2 = StopWacherHelper.DoTimer(() => 2 { 3 var strSpan = str.AsSpan(); 4 5 var splitSapn = splitStr.AsSpan(); 6 7 int m = 0, n = 0; 8 9 for (int i = 0; i < count; i++) 10 { 11 List<string> arr = new List<string>(); 12 13 while (true) 14 { 15 m = n; 16 n = strSpan.IndexOf(splitSapn); 17 if (n > -1) 18 { 19 arr.Add(strSpan.Slice(0, n).ToString()); 20 strSpan = strSpan.Slice(n + splitSapn.Length); 21 } 22 else 23 { 24 break; 25 } 26 } 27 28 } 29 }); 30 31 Console.WriteLine($"Span<T>.Split {count} 次用时:{t2} 毫秒");
四、String.Replace 测试
1 var t1 = StopWacherHelper.DoTimer(() => 2 { 3 for (int i = 0; i < count; i++) 4 { 5 str.Replace(splitStr, replaceStr); 6 } 7 }); 8 9 Console.WriteLine($"String.Replace {count} 次用时:{t1} 毫秒");
1 var t2 = StopWacherHelper.DoTimer(() => 2 { 3 var strSpan = str.AsSpan(); 4 5 var splitSapn = splitStr.AsSpan(); 6 7 int m = 0, n = 0; 8 9 for (int i = 0; i < count; i++) 10 { 11 List<string> arr = new List<string>(); 12 13 while (true) 14 { 15 m = n; 16 n = strSpan.IndexOf(splitSapn); 17 if (n > -1) 18 { 19 arr.Add(strSpan.Slice(0, n).ToString()); 20 strSpan = strSpan.Slice(n + splitSapn.Length); 21 } 22 else 23 { 24 break; 25 } 26 } 27 string.Join(replaceStr, arr); 28 } 29 }); 30 31 Console.WriteLine($"Span<T>.Replace {count} 次用时:{t2} 毫秒");
怎么样,经过上面的测试,是不是觉的Span<T>确实是名不虚传?的确,在上面几个常见场景中,Span<T>的高性能确实不同凡响,差不多是10倍的性能优势!看到这里,小伙伴们是不是觉的字符串操作全改成Span<T>就行了?那下面的两个测试会让大家看清现实,在String.Contains中表现还不如原生的。
一、String.Contains 测试
1 var t1 = StopWacherHelper.DoTimer(() => 2 { 3 for (int i = 0; i < count; i++) 4 { 5 str.Contains(subStr); 6 } 7 }); 8 9 Console.WriteLine($"string.Contains {count} 次用时:{t1} 毫秒");
1 var t2 = StopWacherHelper.DoTimer(() => 2 { 3 var strSpan = str.AsSpan(); 4 5 var subStrSpan = subStr.AsSpan(); 6 7 for (int i = 0; i < count; i++) 8 { 9 strSpan.Contains(subStrSpan, StringComparison.CurrentCulture); 10 } 11 }); 12 13 Console.WriteLine($"Span<T>.Contains {count} 次用时:{t2} 毫秒");
仔细一看,不对啊,Span<T>的Contains里面有其它的大小写和语言相关的判断啊。好,那再换一个原生方法对比测试一下。
二、String.Compare 测试
1 var t1 = StopWacherHelper.DoTimer(() => 2 { 3 for (int i = 0; i < count; i++) 4 { 5 string.Compare(str, subStr, true); 6 } 7 }); 8 9 Console.WriteLine($"string.Compare {count} 次用时:{t1} 毫秒");
1 var t2 = StopWacherHelper.DoTimer(() => 2 { 3 var strSpan = str.AsSpan(); 4 5 var subStrSpan = subStr.AsSpan(); 6 7 for (int i = 0; i < count; i++) 8 { 9 strSpan.Contains(subStrSpan, StringComparison.CurrentCultureIgnoreCase); 10 } 11 }); 12 13 Console.WriteLine($"Span<T>.Contains {count} 次用时:{t2} 毫秒");
还是被反杀了,这说明Span<T>的这个Contains方法可能真的只能在某些地方才能用,不然性能反而会有所下降。
如果对上述感兴趣,可以点击这里下载测试源码,更多请点击左下角的推荐,谢谢~