
暂无个人介绍
继承Thread类的方式实现起来较为简单,但是继承它的类就不能再继承别的类了,因此也就不能继承别的类的有用的方法了。而使用是想Runnable接口的方式就不存在这个问题了,而且这种实现方式将线程主体和线程对象本身分离开来,逻辑上也较为清晰,所以推荐大家更多地采用这种方式。但是对于继承方式调用,使用start方式后实际上里面的属性是不多份的,即多个对象的线程在跑。而接口方式是同一个对象的多个线程在跑。 本文转自博客园沉睡森林@漂在北京的博客,原文链接:线程2种方式的差异,如需转载请自行联系原博主。
原文地址:http://www.3v.org.cn/article.asp?id=164 由于断电或非正常关机而导致MySQL数据库出现错误是非常常见的问题。有两种方法,一种方法使用mysql的check table和repair table 的sql语句,另一种方法是使用MySQL提供的多个myisamchk, isamchk数据检测恢复工具。前者使用起来比较简便。推荐使用。1. check table 和 repair table登陆mysql 终端:mysql -uxxxxx -p dbname> check table tabTest;如果出现的结果说Status是OK,则不用修复,如果有Error,可以用:> repair table tabTest;进行修复,修复之后可以在用check table命令来进行检查。在新版本的phpMyAdmin里面也可以使用check/repair的功能。2. myisamchk, isamchk其中myisamchk适用于MYISAM类型的数据表,而isamchk适用于ISAM类型的数据表。这两条命令的主要参数相同,一般新的系统都使用MYISAM作为缺省的数据表类型,这里以myisamchk为例子进行说明。当发现某个数据表出现问题时可以使用:myisamchk tablename.MYI进行检测,如果需要修复的话,可以使用:myisamchk -of tablename.MYI关于myisamchk的详细参数说明,可以参见它的使用帮助。需要注意的时在进行修改时必须确保MySQL服务器没有访问这个数据表,保险的情况下是最好在进行检测时把MySQL服务器Shutdown掉。-----------------------------另外可以把下面的命令放在你的rc.local里面启动MySQL服务器前:[ -x /tmp/mysql.sock ] && /pathtochk/myisamchk -of /DATA_DIR/*/*.MYI其中的/tmp/mysql.sock是MySQL监听的Sock文件位置,对于使用RPM安装的用户应该是/var/lib/mysql/mysql.sock,对于使用源码安装则是/tmp/mysql.sock可以根据自己的实际情况进行变更,而pathtochk则是myisamchk所在的位置,DATA_DIR是你的MySQL数据库存放的位置。需要注意的时,如果你打算把这条命令放在你的rc.local里面,必须确认在执行这条指令时MySQL服务器必须没有启动! 检测修复所有数据库(表)mysqlcheck -A -o -r -p ---------------------------------------------------------------------------------示例:mysql> check table tabFTPAccountInstances; 本文转自博客园执着的笨蛋的博客,原文链接:如何修复损坏的MySQL数据表[转],如需转载请自行联系原博主。
1. vi /etc/vsftpd/vsftpd.conf 添加: listen=YES tcp_wrappers=YES port_enable=YES ftp_data_port=20 listen_port=21 listen_address=0.0.0.0 port_promiscuous=NO no_anon_password=NO anon_mkdir_write_enable=no 2.将chroot_list_enable=YES前的#去掉 并将chroot_list_file=/etc/vsftpd.chroot_list 前的#去掉 3.创建用户 useradd 用户 passwd 用户 4. vi /etc/vsftpd.chroot_list 将 用户 添加到文件里 5.修改用户的登录路径(主目录) vi /etc/passwd 如:data:x:516:516::/home/data/data:/sbin/nologin 6.启动vsftp service vsftpd restart 本文转自博客园刘凯毅的博客,原文链接:ftp 服务器搭建,如需转载请自行联系原博主。
下载hadoop安装包:http://www.carfab.com/apachesoftware/hadoop/common/hadoop-1.0.2/ 但是没有plugin,我到这个地方下载的:http://ishare.iask.sina.com.cn/f/23642243.html?from=like copy到你的eclipse_home的plugins下面。 配置map/reduce 你可以看到你的hdfs里面的文件了: 本文转自博客园沉睡森林@漂在北京的博客,原文链接:hadoop-eclipse-plugin使用,如需转载请自行联系原博主。
到adb.exe目录 usb连接手机adb pull /system/etc/hosts修改hosts文件adb push hosts /system/etc/hosts查看:adb shellcat /system/etc/hosts 本文转自博客园沉睡森林@漂在北京的博客,原文链接:android修改hosts,如需转载请自行联系原博主。
一、效果图 二、代码实现 2.1 客户端 tablepage.aspx Ext.onReady(function() { Ext.QuickTips.init(); Ext.form.Field.prototype.msgTarget = 'side'; //搜索id var id = new NumberField('tbSearch'); id.style='text-align:center';//设置文本居中 var store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ url: 'tablepage.aspx?method=search', method: 'GET' }), reader: new Ext.data.JsonReader({ totalProperty: 'count', root: 'result' }, [ { name: 'Name' }, { name: 'Id' }, { name: 'Email' }, { name: 'Gender' } ]), baseParams:{ id : '', //用于分页时保存搜索条件 limit: 10 //每页显示数量 } }); //加载数据 store.load(); //遍历数据 // store.each(function(record) { // alert(record.get('name')); // }); // for (var i = 0; i < store.getCount(); i++) { // var record = store.getAt(i); // alert(record.get('name')); // } var dataColumns = new Ext.grid.ColumnModel({ columns: [ new Ext.grid.RowNumberer(), //显示行号 { header: "编 号", dataIndex: 'Id', sortable: true }, { header: "名 称", dataIndex: 'Name' }, { header: "邮 箱", dataIndex: 'Email' }, { header: "性 别", dataIndex: 'Gender' } ], defaults: { align: 'center' } }); var grid = new Ext.grid.GridPanel({ store: store, cm: dataColumns, //columns: [{}] renderTo: Ext.getBody(), //autoExpandColumn: 1, title: '<center style="curor:hand" onclick="window.location.reload();">搜索与分页</center>', autoScroll: true, autoHeight: true, border: true, disableSelection: true, enableHdMenu:false, frame: true, loadMask: { msg: '正在加载数据,请稍侯……' }, //loadMask: true, stripeRows: true, //隔行显示不同颜色 // bodyStyle:'width:99.8%', // autoWidth:true, width: 800, //设置单行选中模式 selModel: new Ext.grid.RowSelectionModel({ singleSelect: false }), //使列自动均分 viewConfig: { forceFit: true }, //搜索条 tbar: new Ext.Toolbar({ items:[ new Ext.form.Label({ text:'编号: ' }), id,{ iconCls: "add", text: '搜索', handler:function(){ //注意 sum 需要等数据加载完毕才能计算出来,不然始终为0 //alert(store.sum('Id')); grid.store.baseParams['id'] = id.getValue();//防止分页时丢失 grid.store.reload(); } } ] }), //底部分页工具条 bbar: new Ext.PagingToolbar({ pageSize: 10,//此处应与limit一致 store: store, displayInfo: true, emptyMsg: '没有记录' }) }); }); 代码说明: 实现了非常简单搜索和分页,需要注意的是关于搜索分页时搜索结果丢失的问题,这里采取了两个步骤:先是在Ext.data.Store的baseParams中声明搜索传值变量,然后再点击搜索按钮时将搜索条件存入到baseParams里,这样分页时条件可以保持下来。 2.2 服务端 tablepage.aspx.cs public override string Search() { int start = -1; int.TryParse(Request.QueryString["start"], out start); int limit = -1; int.TryParse(Request.QueryString["limit"], out limit); string id = Request.QueryString["id"]; IList<User> result = new List<User>(); if (string.IsNullOrEmpty(id)) result = GetPage(ConverToList(dataSource.Values), start, limit); else { int uid; if (int.TryParse(id, out uid)) { if (dataSource.ContainsKey(uid)) result.Add(dataSource[uid]); } } return new StringBuilder().Append("{count:") .Append(1000) .Append(",result:") .Append(JavaScriptConvert.SerializeObject(result)) .Append('}') .ToString(); } #region 数据源 private static IDictionary<int, User> dataSource = new Dictionary<int, User>(); static tablepage() { for (int i = 0; i < 1000; i++) { User user = BuildUser(i); dataSource.Add(user.Id, user); } } private static IList<User> GetPage(IList<User> data, int start, int limit) { IList<User> result = new List<User>(); int length = start + limit; if (length > data.Count) length = data.Count; for (int i = start; i < length; i++) { result.Add(data[i]); } return result; } private static IList<User> ConverToList(ICollection<User> users) { User[] result = new User[users.Count]; users.CopyTo(result, 0); return result; } private static User BuildUser(int number) { return new User() { Id = number, Email = string.Format("test{0}163.com", number), Name = string.Format("test{0}", number), Gender = new Random().Next(2) }; } class User { /// <summary> /// 编号 /// </summary> public int Id { get; set; } /// <summary> /// 邮箱 /// </summary> public string Email { get; set; } /// <summary> /// 名称 /// </summary> public string Name { get; set; } /// <summary> /// 性别 0 女 1 男 /// </summary> public int Gender { get; set; } } #endregion 代码说明: 这里仍然没有连接数据库,模拟数据与分页查询。 2.3 存储过程 CREATE PROCEDURE dbo.DataPager ( @StartIndex INT = 0 , @Limit INT = 15, @RowsCount INT = 0 OUTPUT, -- 输出记录总行数 @SQLString VARCHAR(500) )AS SET NOCOUNT ON SELECT IDENTITY(INT,1,1) AS [NewID],* INTO #TMP_ZSFLZ1 FROM [TB_XJYJZ] WHERE 1=2 INSERT INTO #TMP_ZSFLZ1 EXEC sp_executesql @SQLString --总行数 SELECT @RowsCount = COUNT([NewID]) FROM #TMP_ZSFLZ SET @StartIndex = @StartIndex + 1 SELECT * FROM #TMP_ZSFLZ tz WHERE [NewID] BETWEEN @StartIndex AND @StartIndex + @Limit - 1 DROP TABLE #TMP_ZSFLZ RETURNGO 代码说明: 虽然本文没有用到,倒是实际中肯定要用到的,这里写一个样例,仅供参考(注意:这里是SQL2000的例子)。 三、下载 ExtJS2009-11-30 本文转自博客园农民伯伯的博客,原文链接:ExtJs 备忘录(6)—— GirdPanl表格(二) [ 搜索分页 ],如需转载请自行联系原博主。
一、准备 1.1 了解关于Google IO大会关于Adapter的优化,参考以下文章: Android开发之ListView 适配器(Adapter)优化 Android开发——09Google I/O之让Android UI性能更高效(1) PDF下载:Google IO.pdf 1.2 准备测试代码: Activity private TestAdapter mAdapter; private String[] mArrData; private TextView mTV; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mTV = (TextView) findViewById(R.id.tvShow); mArrData = new String[1000]; for (int i = 0; i < 1000; i++) { mArrData[i] = "Google IO Adapter" + i; } mAdapter = new TestAdapter(this, mArrData); ((ListView) findViewById(android.R.id.list)).setAdapter(mAdapter); } 代码说明:模拟一千条数据,TestAdapter继承自BaseAdapter,main.xml见文章末尾下载。 二、测试 测试方法:手动滑动ListView至position至50然后往回滑动,充分利用convertView不等于null的代码段。 2.1 方案一 按照Google I/O介绍的第二种方案,把item子元素分别改为4个和10个,这样效果更佳明显。 2.1.1 测试代码 private int count = 0; private long sum = 0L; @Override public View getView(int position, View convertView, ViewGroup parent) { //开始计时 long startTime = System.nanoTime(); if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item_icon_text, null); } ((ImageView) convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon); ((TextView) convertView.findViewById(R.id.text1)).setText(mData[position]); ((ImageView) convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon); ((TextView) convertView.findViewById(R.id.text2)).setText(mData[position]); //停止计时 long endTime = System.nanoTime(); //计算耗时 long val = (endTime - startTime) / 1000L; Log.e("Test", "Position:" + position + ":" + val); if (count < 100) { if (val < 1000L) { sum += val; count++; } } else mTV.setText(String.valueOf(sum / 100L));//显示统计结果 return convertView; } 2.1.2 测试结果(微秒除以1000,见代码) 次数 4个子元素 10个子元素 第一次 366 723 第二次 356 689 第三次 371 692 第四次 356 696 第五次 371 662 2.2 方案二 按照Google I/O介绍的第三种方案,是把item子元素分别改为4个和10个。 2.2.1 测试代码 private int count = 0; private long sum = 0L; @Override public View getView(int position, View convertView, ViewGroup parent) { // 开始计时 long startTime = System.nanoTime(); ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item_icon_text, null); holder = new ViewHolder(); holder.icon1 = (ImageView) convertView.findViewById(R.id.icon1); holder.text1 = (TextView) convertView.findViewById(R.id.text1); holder.icon2 = (ImageView) convertView.findViewById(R.id.icon2); holder.text2 = (TextView) convertView.findViewById(R.id.text2); convertView.setTag(holder); } else{ holder = (ViewHolder)convertView.getTag(); } holder.icon1.setImageResource(R.drawable.icon); holder.text1.setText(mData[position]); holder.icon2 .setImageResource(R.drawable.icon); holder.text2.setText(mData[position]); // 停止计时 long endTime = System.nanoTime(); // 计算耗时 long val = (endTime - startTime) / 1000L; Log.e("Test", "Position:" + position + ":" + val); if (count < 100) { if (val < 1000L) { sum += val; count++; } } else mTV.setText(String.valueOf(sum / 100L));// 显示统计结果 return convertView; } } static class ViewHolder { TextView text1; ImageView icon1; TextView text2; ImageView icon2; } 2.2.2 测试结果(微秒除以1000,见代码) 次数 4个子元素 10个子元素 第一次 311 417 第二次 291 441 第三次 302 462 第四次 286 444 第五次 299 436 2.3 方案三 此方案为“Henry Hu”提示,API Level 4以上提供,这里顺带测试了一下不使用静态内部类情况下性能。 2.3.1 测试代码 @Override public View getView(int position, View convertView, ViewGroup parent) { // 开始计时 long startTime = System.nanoTime(); if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item_icon_text, null); convertView.setTag(R.id.icon1, convertView.findViewById(R.id.icon1)); convertView.setTag(R.id.text1, convertView.findViewById(R.id.text1)); convertView.setTag(R.id.icon2, convertView.findViewById(R.id.icon2)); convertView.setTag(R.id.text2, convertView.findViewById(R.id.text2)); } ((ImageView) convertView.getTag(R.id.icon1)).setImageResource(R.drawable.icon); ((ImageView) convertView.getTag(R.id.icon2)).setImageResource(R.drawable.icon); ((TextView) convertView.getTag(R.id.text1)).setText(mData[position]); ((TextView) convertView.getTag(R.id.text2)).setText(mData[position]); // 停止计时 long endTime = System.nanoTime(); // 计算耗时 long val = (endTime - startTime) / 1000L; Log.e("Test", "Position:" + position + ":" + val); if (count < 100) { if (val < 1000L) { sum += val; count++; } } else mTV.setText(String.valueOf(sum / 100L) + ":" + nullcount);// 显示统计结果 return convertView; } 2.3.2 测试结果(微秒除以1000,见代码) 第一次:450 第二次:467 第三次:472 第四次:451 第五次:441 四、总结 4.1 首先有一个认识是错误的,我们先来看截图: 可以发现,只有第一屏(可视范围)调用getView所消耗的时间远远多于后面的,通过对 convertView == null内代码监控也是同样的结果。也就是说ListView仅仅缓存了可视范围内的View,随后的滚动都是对这些View进行数据更新。不管你有多少数据,他都只用ArrayList缓存可视范围内的View,这样保证了性能,也造成了我以为ListView只缓存View结构不缓存数据的假相(不会只有我一人这么认为吧- - #)。这也能解释为什么GOOGLE优化方案一比二高很多的原因。那么剩下的也就只有findViewById比较耗时了。据此大家可以看看AbsListView的源代码,看看 obtainView这个方法内的代码及RecycleBin这个类的实现,欢迎分享。 此外了解这个原理了,那么以下代码不运行你可能猜到结果了: if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item_icon_text, null); ((ImageView) convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon); ((TextView) convertView.findViewById(R.id.text1)).setText(mData[position]); ((ImageView) convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon); ((TextView) convertView.findViewById(R.id.text2)).setText(mData[position]); } else return convertView; 没错,你会发现滚动时会重复显示第一屏的数据! 子控件里的事件因为是同一个控件,也可以直接放到convertView == null 代码块内部,如果需要交互数据比如position,可以通过tag方式来设置并获取当前数据。 4.2 本文方案一与方案二对比 这里推荐如果只是一般的应用(一般指子控件不多),无需都是用静态内部类来优化,使用第二种方案即可;反之,对性能要求较高时可采用。此外需要提醒的是这里也是用空间换时间的做法,View本身因为setTag而会占用更多的内存,还会增加代码量;而findViewById会临时消耗更多的内存,所以不可盲目使用,依实际情况而定。 4.3 方案三 此方案为“Henry Hu”提示,API Level 4以上支持,原理和方案三一致,减少findViewById次数,但是从测试结果来看效果并不理想,这里不再做进一步的测试。 五、推荐文章 Android,谁动了我的内存(1) Android 内存泄漏调试 本文转自博客园农民伯伯的博客,原文链接:[Android]ListView性能优化之视图缓存,如需转载请自行联系原博主。
一、结构 public abstract class SimpleCusrorTreeAdapter extends ResourceCusorTreeAdpater java.lang.Object android.widget.BaseExpandableListAdapter android.widget.CursorTreeAdapter android.widget.ResourceCusorTreeAdapter android.widget.SimpleCursorTreeAdapter 二、概述 这是一个用起来很方便的适配器类,它主要将Cursor与在XML文件中定义的TextView或ImageView进行映射。比如,你想设定要展示三列,那么当做好绑定之后,视图就会展示你设定好的那些列;当然了,视图的外观是定义在XML文件里面的,你只需用这个类与视图做好绑定就可以了。(译者注:Android推荐我们尽可能的将组视图和子视图分离开,也就是说不要把整体定义在一个布局文件当中。)与视图绑定有两个阶段。第一阶段:如果使用SimpleCursorTreeAdapter.ViewBinder时,那么就会调用setViewValue(android.view.View, android.database.Cursor, int)方法。该方法返回true就说明绑定成功,否则返回false,这就到了第二阶段,SimpleCursorAdapter内部开始自行绑定,过程是这样的,若绑定到TextView上,调用setViewText(TextView, String);若绑定到ImageView上,调用setViewImage(ImageView, String),如果视图不是TextView或ImageView则抛出IllegalStateException异常。 三、内部类 public interface SimpleCursorTreeAdapter.ViewBinder 这个内部接口可以在外部通过SimpleCursorTreeAdapter.ViewBinder的方式进行 Cursor与View的绑定。 四、构造函数 public SimpleCursorTreeAdapter (Context context, Cursor cursor, int collapsedGroupLayout, int expandedGroupLayout, String[] groupFrom, int[] groupTo, int childLayout, int lastChildLayout, String[] childFrom, int[] childTo) 构造函数。 参数 context 上下文,多指ExpandableListView的上下文 cursor 数据库游标 collapsedGroupLayout 布局资源文件标识ID,其定义的是收缩时的ExpandableListView布局样式,并且内部至少要包含参数“groupTo”中指定的视图ID。 expandedGroupLayout 布局资源文件标识ID,其定义的是展开时的ExpandableListView布局样式,并且内部至少要包含参数“groupTo”中指定的视图ID。 groupFrom 列名列表,显示ExpandableListView的组节点。 groupTo 展示参数“groupFrom”中的列,也就是说ExpandableListView中的视图显示的是参数 “groupFrom”的列值,它们应该都是TextView或是ImageView。 childLayout 布局资源文件标识ID,其定义的是子视图的布局样式 (不包括最后一个子视图),内部至少要包含参数 “childTo”中指定的视图ID。lastChildLayout布局资源文件标识ID,其定义的是最后一个子视图的布局样式,内部至少要包含参数“childTo”中指定的视图ID。 lastChildLayout 布局资源文件标识ID,其定义的是最后一个子视图的布局样式,内部至少要包含参数“childTo”中指定的视图ID。lastChildLayout布局资源文件标识ID,其定义的是最后一个子视图的布局样式,内部至少要包含参数“childTo”中指定的视图ID。 childFrom 列名列表,显示ExpandableListView的子节点。 childTo 展示参数“childFrom ”中的列,也就是说ExpandableListView中的视图显示的是参数 “childFrom ”的列值,它们应该都是TextView或是ImageView。 public SimpleCursorTreeAdapter (Context context, Cursor cursor, int collapsedGroupLayout, int expandedGroupLayout, String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom, int[] childTo) 构造函数。(译者注:该构造函数只是少了一个参数lastChildLayout) 参数 context 上下文,多指ExpandableListView的上下文 cursor 数据库游标 collapsedGroupLayout 布局资源文件标识ID,其定义的是收缩时的ExpandableListView布局样式,并且内部至少要包含参数“groupTo”中指定的视图ID。 expandedGroupLayout 布局资源文件标识ID,其定义的是展开时的ExpandableListView布局样式,并且内部至少要包含参数“groupTo”中指定的视图ID。 groupFrom 列名列表,显示ExpandableListView的组节点。 groupTo 展示参数“groupFrom”中的列,也就是说ExpandableListView中的视图显示的是参数 “groupFrom”的列值,它们应该都是TextView或是ImageView。 childLayout 布局资源文件标识ID,其定义的是子视图的布局样式 (不包括最后一个子视图),内部至少要包含参数 “childTo”中指定的视图ID。lastChildLayout布局资源文件标识ID,其定义的是最后一个子视图的布局样式,内部至少要包含参数“childTo”中指定的视图ID。 childFrom 列名列表,显示ExpandableListView的子节点。 childTo 展示参数“childFrom ”中的列,也就是说ExpandableListView中的视图显示的是参数 “childFrom ”的列值,它们应该都是TextView或是ImageView。 public SimpleCursorTreeAdapter (Context context, Cursor cursor, int groupLayout, String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom, int[] childTo) 构造函数。 参数 context 上下文,多指ExpandableListView的上下文 cursor 数据库游标 groupLayout 显示组元素的资源文件。该资源文件定义了如何显示组元素。该布局文件必须至少包括groupTo中所定义的View。(即groupTo中的View id数组必须都在该布局文件中找到) groupFrom 列名列表,显示ExpandableListView的组节点。 groupTo 展示参数“groupFrom”中的列,也就是说ExpandableListView中的视图显示的是参数 “groupFrom”的列值,它们应该都是TextView或是ImageView。 childLayout 布局资源文件标识ID,其定义的是子视图的布局样式 (不包括最后一个子视图),内部至少要包含参数 “childTo”中指定的视图ID。lastChildLayout布局资源文件标识ID,其定义的是最后一个子视图的布局样式,内部至少要包含参数“childTo”中指定的视图ID。 childFrom 列名列表,显示ExpandableListView的子节点。 childTo 展示参数“childFrom ”中的列,也就是说ExpandableListView中的视图显示的是参数 “childFrom ”的列值,它们应该都是TextView或是ImageView。 五、公共方法 public SimpleCursorAdapter.ViewBinder getViewBinder () 返回SimpleCursorTreeAdapter.ViewBinder引用,这个ViewBinder用来将数据绑定到 视图上的。 返回值 如果ViewBinder不存在,则返回null。 参考 setViewBinder(android.widget.SimpleCursorTreeAdapter.ViewBinder) public void setViewBinder (SimpleCursorTreeAdapter.ViewBinder viewBinder) . 设置视图绑定器。 参数 viewBinder 视图绑定器。可以设置为null来删除已经存在的绑定器。 参考 getViewBinder() public void setViewText (TextView v, String text) 仅当ViewBinder不存在或是当ViewBinder不为TextView绑定时(也就是setViewValue()返回false),则这个方法会被bindView()调用,以便为TextView设置文本。可重写适配器从数据库中检索过滤字符串。 参数 v 文本控件引用 value 为文本控件设置的文本信息(译者注:是从Cursor获取到的)。 六、受保护方法 protected void bindChildView (View view, Context context, Cursor cursor, boolean isExpanded) 通过参数cursor将数据绑定到已有的子视图上。。 参数 view 已有视图,返回之前调用newChildView创建的视图。 context 应用程序上下文 cursor 用于获取数据的Coursor。Coursor已经移到正确的位置。 isLastChild 子元素是否处于组中的最后一个 protected void bindGroupView (View view, Context context, Cursor cursor, boolean isExpanded) 通过参数cursor将数据绑定到已有组视图上。 参数 view 已有组视图,返回之前调用newGroupView创建的视图。 context 应用程序上下文 cursor 用于获取数据的Coursor。Coursor已经移到正确的位置。 isExpanded 组视图是否呈展开状态 protected void setViewImage (ImageView v, String value) 这个方法会被bindView()调用,以便为ImageView设置图片。默认情况下,参数value作为图片资源ID来看待,否则会视为图片的Uri。 另外还可以通过过滤器来获得更灵活的设置。 参数 v 图片控件引用 value 图片资源ID,是从Cursor获取到的。 七、补充 文章精选 android播放器(music player)源码分析2 示例代码 SimpleCursorTreeAdapter(深夜未眠).rar SimpleCursorTreeAdapter.ViewBinder 译者署名: 深夜未眠 译者链接:http://chris1012f.javaeye.com/ 翻译时间:2011-3-3 版本:Android 3.0 r1 结构 继承关系 public static interface SimpleCusrorTreeAdapter.ViewBinder java.lang.Object android.widget.SimpleCursorTreeAdapter.ViewBinder 类概述 这个内部接口可以在外部通过SimpleCursorTreeAdapter.ViewBinder的方式进行 Cursor与View的绑定。Android推荐我们采用这种方式进行绑定操作,而不是沿用SimpleCursorTreeAdapter内部的方式。 参见 setViewImage(ImageView, String) setViewText(TextView, String) 公共方法 public abstract boolean setViewValue (View view, Cursor cursor, int columnIndex) 将指定的列数据绑定到指定的视图上。当ViewBinder处理绑定时,这个方法必须返回true;否则SimpleAdapter将尝试通过其内部默认的方法绑定数据。 参数 view 被绑定的视图。 cursor 数据库游标,绑定数据从它这里获取 columnIndex 列位置,能够在数据库游标中寻找到。 返回值 返回true意味着数据与视图已经绑定上,否则为未绑定上。 本文转自博客园农民伯伯的博客,原文链接:Android中文API (109) —— SimpleCursorTreeAdapter,如需转载请自行联系原博主。
测试 Android开发环境包含一套集成的测试框架,用来帮助开发者测试应用程序的各个方面。 基础 开始学习如果使用框架来为你的程序创建测试,请阅读章节测试基础(Testing Fundamentals)。 概念 * Activity测试主要讨论如何测试activities。这一章描述了测试工具如何让你在常规的应用程序生命周期之外控制Activity。它还列出了你应该测试activity的哪些功能并提供了一些测试Android用户界面的意见。 * Content Provider测试主要讨论如何测试内容提供者。这一章介绍了你可以使用的模拟系统对象,给出了设计内容提供者的相关建议以便他们能被测试,并且列出了你应该测试的提供者功能。 * Service测试主要讨论测试服务。它同样列出了你应该测试的服务功能。 * 测试什么(What to Test)一章是关于你应该进行哪些种类的测试的概述。它主要讨论对Android系统层面的测试,这可能影响到你应用程序中的每个组件。 过程 * 使用ADT在Eclipse下测试一章讲述了在装有ADT的Eclipse中如何创建和运行测试。 * 在其他IDE中测试一章讲述了如何使用命令行工具创建和运行测试。 教程 * Hello,Testing教程介绍了基本的测试概念和过程。 * 如果需要更高级的教程,请尝试Activity Testing,它通过一个更加复杂的场景指导你如何测试。 工具 * UI/Application Exerciser Monkey,通常被叫做Monkey,是一个命令行工具,它能向设备发送按键、触碰、手势的伪随机流。 * monkeyrunner工具是一套API和执行环境。你在Python程序中使用monkeyrunner来测试程序和设备。 本文转自博客园农民伯伯的博客,原文链接:Android开发者指南(20) —— Testing,如需转载请自行联系原博主。
翻阅查找ScrollView的文档并搜索了一下没有发现直接设置的属性和方法,这里通过继承来达到这一目的。 /** * 快/慢滑动ScrollView * @author 农民伯伯 * */ public class SlowScrollView extends ScrollView { public SlowScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public SlowScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public SlowScrollView(Context context) { super(context); } /** * 滑动事件 */ @Override public void fling(int velocityY) { super.fling(velocityY / 4); } } 代码说明: 重点在"velocityY / 4",这里意思是滑动速度减慢到原来四分之一的速度,这里大家可以根据自己的需求加快或减慢滑动速度。 本文转自博客园农民伯伯的博客,原文链接:Android控制ScrollView滑动速度,如需转载请自行联系原博主。
相关内容: ADT 14.0.0是为了SDK Tool r14的使用而设计的。如果您还没有在SDK中安装SDK Tool r14,那么请使用Android SDK里的SDK管理器进行安装。 构建系统 · 当你开打Eclipse中的项目时,如果有必要,ADT会自动将default.properties文件重命名为project.properties以及将build.properties文件重命名为ant.properties。 · 修改了在Eclipse中构建库项目的方式。 · 将Eclipse中的javac的输出路径从bin/改到bin/classes。 · 改进了Build的方式,使得资源的编译运行不那么频繁。Builds不再会因为仅仅修改了strings或layouts(除非你增加一个新的id)而运行,也不会为了每个库项目运行一次。 · 引入了“PNG压缩缓存”,只运行正在被修改的PNG文件,而不再是随时运行所有PNG文件了。 · 修改的资源编译方式,将不再在常规的保存操作后执行编译,只有当运行或调试时才执行(构建选项允许你禁用打包步骤,在ADT12中被引入,现在是默认的)。 想要全面的了解更多关于构建系统的变化以及你所要做的支持变更工作,详见Android Tools Project site. 一般改进 · 增加了一个欢迎向导,以帮助搭建初始的Android开发环境 。(更多信息) · 集成了Android Asset Studio, 可以帮助你设计进程,菜单和标签等东西的图标。 (更多信息) · 重组了Logcat的视图并新增了根据应用程序名称或PID对log进行查看及过滤的功能。 (更多信息) · 重组了SDK的管理界面。(更多信息) · 重组了新建项目以及新建XML文件的向导,使之拥有多个界面。 样本项目将被复制进工作区中,对其进行修改和删除都不会影响原有副本。 (更多信息) · 移除了对于Eclipse GEF的依赖。 XML 和Java编辑器 · 增加了新的XML格式,将根据标准的Android编码风格对所有XML文件进行格式化。格式化器还可以根据推荐的顺序或任何对于布局编辑器的修改来对属性重新排列。 (更多信息) · 新增了“转到匹配”(CTRL-SHIFT-P)的功能,可以让你在打开和关闭的XML文件标签间自由跳转。 · 增加了“选择封闭元素”功能对于Mac的支持。 · 增加了对于提取字符串中插入符号的快速修复功能 。(更多信息) · 改进的“智能缩进”,使得在XML编辑器中按回车键时可以自动缩进或取消缩进。(更多信息) 布局编辑器 · 增加了对于拖动和缩放功能的提示和反馈意见。例如,当拖动一个相对布局时,建议的约束将显示出来。当进行缩放时,一个新的坐标会被展示出来。(更多信息) · 增加了抑制渲染保真度警告的能力。 (更多信息) · 增加了“移除容器”视觉重构,移除了顶层的子容器,并在必要时转移命名空间和布局属性(更多信息)。 · 对于父菜单的属性提供了右拉菜单,这在子菜单完全覆盖父菜单而使其难以选择自身时特别有用。 · 改进的在菜单中访问属性的方法。每个视图最频繁设置的属性都列在菜单的顶部。“属性”菜单提供了访问最近设置的属性的功能,这些属性根据其定义的视图进行组织,布局属性和所有属性都可以按字母顺序排序。 (更多信息). Bug 修复 修正了许多错误并增加了一定的改进,特别是对于一些在Linux上的关键错误的修复。 本文转自博客园农民伯伯的博客,原文链接:Android 中文 SDK —— ADT 14.0.0 (ADT14插件更新说明),如需转载请自行联系原博主。
一、目标 下图是我们要实现的目标: 二、实现 原理非常简单,首先制作样式模版,可以参照文章2,将排版好的Word另存为html,然后复制粘贴到aspx页面中,然后从数据库读取表以及字段信息,动态的插入表名和字段信息。 2.1 SqlSchemaProvider.cs //==============================================================================//// 作 者:农民伯伯// 邮 箱:over140@gmail.com// 博 客:http://over140.cnblogs.com/// 时 间:2009-9-9// 描 述:获取SQL SERVER 元数据////==============================================================================using System;using System.Collections.Generic;using System.Text;using System.Data;using System.Data.SqlClient;using System.Linq;public sealed class SqlSchemaProvider { #region Constructor public SqlSchemaProvider(string connectstring) { ConnectString = connectstring; } #endregion #region GetTableColumns public IList<ColumnInfo> GetTableColumns(string tableName) { IList<ColumnInfo> result = new List<ColumnInfo>(); SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(ConnectString); using (SqlConnection conn = new SqlConnection(scsb.ConnectionString)) { conn.Open(); SqlCommand cmd = new SqlCommand(SQL2000_GetTableColumns, conn); cmd.Parameters.Add(new SqlParameter("@DatabaseName", scsb.InitialCatalog)); cmd.Parameters.Add(new SqlParameter("@SchemaName", "dbo")); cmd.Parameters.Add(new SqlParameter("@TableName", tableName)); SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); while (reader.Read()) { result.Add(new ColumnInfo() { Name = reader.GetString(0), DataType = reader.GetString(1), Length = reader.GetInt32(3), Nullable = reader.GetString(6).Trim().Equals("YES") ? true : false, DefaultValue = reader.IsDBNull(7) ? "" : reader[7].ToString(), Identity = reader.GetInt32(8), IdentitySeed = Convert.ToInt32(reader.GetString(12)), IdentityIncrement = Convert.ToInt32(reader.GetString(13)), ColumnDesc = reader.GetString(17) }); } reader.Close(); } return result; } public IList<string> GetTables() { IList<string> result = new List<string>(); SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(ConnectString); using (SqlConnection conn = new SqlConnection(scsb.ConnectionString)) { conn.Open(); SqlCommand cmd = new SqlCommand(SQL2000_GetTables, conn); SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); while (reader.Read()) { result.Add(reader.GetString(0)); } reader.Close(); } return result; } #region Type Maps private string GetCSharpType(string type) { if (string.IsNullOrEmpty(type)) return "string"; string reval = string.Empty; switch (type.ToLower()) { case "varchar": case "nchar": case "ntext": case "text": case "char": case "nvarchar": reval = "string"; break; case "int": reval = "int"; break; case "smallint": reval = "Int16"; break; case "bigint": reval = "Int64"; break; case "float": reval = "double"; break; case "bit": reval = "bool"; break; case "decimal": case "smallmoney": case "money": case "numeric": reval = "decimal"; break; case "binary": reval = "System.Byte[]"; break; case "real": reval = "System.Single"; break; case "datetime": case "smalldatetime": case "timestamp": reval = "System.DateTime"; break; case "tinyint": reval = "System.Byte"; break; case "uniqueidentifier": reval = "System.Guid"; break; case "image": case "varbinary": reval = "System.Byte[]"; break; case "Variant": reval = "Object"; break; default: reval = "string"; break; } return reval; } #endregion #endregion #region SQL Templates #region GetTableColumns private const string SQL2000_GetTables = @" SELECT object_name(so.id) AS OBJECT_NAME, user_name(so.uid) AS USER_NAME, so.type AS TYPE, so.crdate AS DATE_CREATED, fg.file_group AS FILE_GROUP, so.id AS OBJECT_ID FROM dbo.sysobjects so LEFT JOIN ( SELECT s.groupname AS file_group, i.id AS id FROM dbo.sysfilegroups s INNER JOIN dbo.sysindexes i ON i.groupid = s.groupid WHERE i.indid < 2 ) AS fg ON so.id = fg.id WHERE so.type = N'U' AND permissions(so.id) & 4096 <> 0 AND ObjectProperty(so.id, N'IsMSShipped') = 0 ORDER BY user_name(so.uid), object_name(so.id)"; private const string SQL2000_GetTableColumns = @" SELECT clmns.[name] AS [Name], usrt.[name] AS [DataType], ISNULL(baset.[name], N'') AS [SystemType], CAST(CASE WHEN baset.[name] IN (N'char', N'varchar', N'binary', N'varbinary', N'nchar', N'nvarchar') THEN clmns.prec ELSE clmns.length END AS INT) AS [Length], CAST(clmns.xprec AS TINYINT) AS [NumericPrecision], CAST(clmns.xscale AS INT) AS [NumericScale], CASE CAST(clmns.isnullable AS BIT) WHEN 1 THEN 'YES' ELSE 'NO' END AS [Nullable], defaults.text AS [DefaultValue], CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsIdentity') AS INT) AS [Identity], CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsRowGuidCol') AS INT) AS IsRowGuid, CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsComputed') AS INT) AS IsComputed, CAST(COLUMNPROPERTY(clmns.id, clmns.[name], N'IsDeterministic') AS INT) AS IsDeterministic, CAST(CASE COLUMNPROPERTY(clmns.id, clmns.[name], N'IsIdentity') WHEN 1 THEN IDENT_SEED(QUOTENAME(stbl.[name]) + '.' + QUOTENAME(tbl.[name])) ELSE 0 END AS NVARCHAR(40)) AS [IdentitySeed], CAST(CASE COLUMNPROPERTY(clmns.id, clmns.[name], N'IsIdentity') WHEN 1 THEN IDENT_INCR(QUOTENAME(stbl.[name]) + '.' + QUOTENAME(tbl.[name])) ELSE 0 END AS NVARCHAR(40)) AS [IdentityIncrement], cdef.[text] AS ComputedDefinition, clmns.[collation] AS Collation, CAST(clmns.colid AS int) AS ObjectId, isnull(prop.value, '') AS ColumnDesc FROM dbo.sysobjects AS tbl INNER JOIN dbo.sysusers AS stbl ON stbl.[uid] = tbl.[uid] INNER JOIN dbo.syscolumns AS clmns ON clmns.id=tbl.id LEFT JOIN dbo.systypes AS usrt ON usrt.xusertype = clmns.xusertype LEFT JOIN dbo.sysusers AS sclmns ON sclmns.uid = usrt.uid LEFT JOIN dbo.systypes AS baset ON baset.xusertype = clmns.xtype and baset.xusertype = baset.xtype LEFT JOIN db.syscomments AS defaults ON defaults.id = clmns.cdefault LEFT JOIN dbo.syscomments AS cdef ON cdef.id = clmns.id AND cdef.number = clmns.colid LEFT OUTER JOIN sysproperties prop ON clmns.id = prop.id AND clmns.colid = prop.smallid WHERE (tbl.[type] = 'U' OR tbl.[type] = 'S') AND stbl.[name] = 'dbo' AND tbl.[name] = @TableName ORDER BY clmns.colorder"; #endregion #endregion #region Properties public string ConnectString { get; set; } #endregion } 代码说明: 这里是获取数据库2000元数据的类,如果其他数据库可参照文章1。 2.2 ColumnInfo.cs using System;using System.Data;using System.Configuration;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;/// <summary>///ColumnInfo 的摘要说明/// </summary>public class ColumnInfo { public ColumnInfo() { // //TODO: 在此处添加构造函数逻辑 // } /// <summary> /// 列名 /// </summary> public string Name { get; set; } /// <summary> /// 数据类型 /// </summary> public string DataType { get; set; } /// <summary> /// 长度 /// </summary> public int Length { get; set; } /// <summary> /// 是否允许空 /// </summary> public bool Nullable { get; set; } /// <summary> /// 1 标识 /// </summary> public int Identity { get; set; } /// <summary> /// 1 标识种子 /// </summary> public int IdentitySeed { get; set; } /// <summary> /// 标识增量 /// </summary> public int IdentityIncrement { get; set; } /// <summary> /// 说明 /// </summary> public string ColumnDesc { get; set; } /// <summary> /// 默认值 /// </summary> public string DefaultValue { get; set; } } 代码说明: 数据库字段Model。 2.3 Default.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %><html><head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <meta name="Generator" content="Microsoft Word 11 (filtered)"> <title>数据库文档</title> <style> <!-- /* Font Definitions */ @font-face { font-family: 宋体; panose-1: 2 1 6 0 3 1 1 1 1 1; } @font-face { font-family: 楷体_GB2312; panose-1: 2 1 6 9 3 1 1 1 1 1; } @font-face { font-family: "\@宋体"; panose-1: 2 1 6 0 3 1 1 1 1 1; } @font-face { font-family: "\@楷体_GB2312"; panose-1: 2 1 6 9 3 1 1 1 1 1; } /* Style Definitions */p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; text-justify: inter-ideograph; font-size: 10.5pt; font-family: "Times New Roman"; } p.MsoFooter, li.MsoFooter, div.MsoFooter { margin: 0cm; margin-bottom: .0001pt; layout-grid-mode: char; font-size: 9.0pt; font-family: "Times New Roman"; } /* Page Definitions */@page Section1 { size: 595.3pt 841.9pt; margin: 72.0pt 90.0pt 72.0pt 90.0pt; layout-grid: 15.6pt; } div.Section1 { page: Section1; } -- ></style></head><body lang="ZH-CN" style='text-justify-trim: punctuation'> <div class="Section1" style='layout-grid: 15.6pt'> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US" style='font-size: 42.0pt'>&nbsp;</span></p> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US" style='font-size: 42.0pt'>&nbsp;</span></p> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-size: 42.0pt; font-family: 楷体_GB2312'>数据库文档</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> <div align="center"> <table class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0" style='margin-left: 34.6pt; border-collapse: collapse; border: none'> <tr style='height: 15.6pt'> <td width="85" valign="top" style='width: 64.0pt; border: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>版本号</span></p> </td> <td width="131" valign="top" style='width: 98.6pt; border: solid windowtext 1.0pt; border-left: none; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>日期</span></p> </td> <td width="132" valign="top" style='width: 98.65pt; border: solid windowtext 1.0pt; border-left: none; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>负责人</span></p> </td> <td width="132" valign="top" style='width: 98.65pt; border: solid windowtext 1.0pt; border-left: none; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>备注</span></p> </td> </tr> <tr style='height: 15.6pt'> <td width="85" valign="top" style='width: 64.0pt; border: solid windowtext 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">0.1</span></p> </td> <td width="131" valign="top" style='width: 98.6pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">2009-9-9</span></p> </td> <td width="132" valign="top" style='width: 98.65pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>农民伯伯</span></p> </td> <td width="132" valign="top" style='width: 98.65pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">&nbsp;</span></p> </td> </tr> <tr style='height: 15.6pt'> <td width="85" valign="top" style='width: 64.0pt; border: solid windowtext 1.0pt; border-top: none; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">&nbsp;</span></p> </td> <td width="131" valign="top" style='width: 98.6pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">&nbsp;</span></p> </td> <td width="132" valign="top" style='width: 98.65pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">&nbsp;</span></p> </td> <td width="132" valign="top" style='width: 98.65pt; border-top: none; border-left: none; border-bottom: solid windowtext 1.0pt; border-right: solid windowtext 1.0pt; padding: 0cm 5.4pt 0cm 5.4pt; height: 15.6pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span lang="EN-US">&nbsp;</span></p> </td> </tr> </table> </div> <asp:Repeater ID="rptData" runat="server"> <HeaderTemplate> </HeaderTemplate> <ItemTemplate> <p class="MsoNormal"><span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"><span lang="EN-US">&nbsp;</span></p> <p class="MsoNormal"> <b><span style='font-size: 12.0pt; font-family: 宋体'>表</span></b><b><span lang="EN-US" style='font-size: 12.0pt'>&nbsp; </span></b><b><span style='font-size: 12.0pt; font-family: 宋体'> 名:</span></b><b><span lang="EN-US" style='font-size: 12.0pt'><%#Container.DataItem%></span></b></p> <p class="MsoNormal"> <b><span style='font-size: 12.0pt; font-family: 宋体; background: yellow'>表说明:</span></b></p> <table class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0" style='border-collapse: collapse; border: none'> <tr> <td width="130" valign="top" style='width: 97.7pt; border: solid windowtext 1.0pt; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>字段名</span></p> </td> <td width="81" valign="top" style='width: 60.95pt; border: solid windowtext 1.0pt; border-left: none; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>数据类型</span></p> </td> <td width="50" valign="top" style='width: 37.3pt; border: solid windowtext 1.0pt; border-left: none; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>长度</span></p> </td> <td width="67" valign="top" style='width: 49.95pt; border: solid windowtext 1.0pt; border-left: none; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>允许空</span></p> </td> <td width="67" valign="top" style='width: 49.95pt; border: solid windowtext 1.0pt; border-left: none; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>默认值</span></p> </td> <td width="88" valign="top" style='width: 65.85pt; border: solid windowtext 1.0pt; border-left: none; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>其他</span></p> </td> <td width="86" valign="top" style='width: 64.4pt; border: solid windowtext 1.0pt; border-left: none; background: #E0E0E0; padding: 0cm 5.4pt 0cm 5.4pt'> <p class="MsoNormal" align="center" style='text-align: center'> <span style='font-family: 宋体'>字段说明</span></p> </td> </tr> <%# ColumnInfo(Container.DataItem.ToString()) %> </table> </ItemTemplate> <FooterTemplate> </FooterTemplate> </asp:Repeater> <p class="MsoNormal"> <span lang="EN-US">&nbsp;</span></p> </div></body></html> 代码说明: 如果大家觉得截图上就是你要的文档格式,这里不用修改直接运行就行了,要是有自己的格式的话需要制作模版,参照文章2,对应修改就行。 2.4 Default.aspx.cs using System;using System.Configuration;using System.Data;using System.Linq;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.HtmlControls;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Xml.Linq;using System.Collections;using System.Collections.Generic;using System.Text;public partial class _Default : System.Web.UI.Page { private const string connstr = "Data Source=SERVER;Initial Catalog=Test;User ID=sa;Password=sa"; private readonly SqlSchemaProvider provider = new SqlSchemaProvider(connstr); protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { this.rptData.DataSource = provider.GetTables(); this.rptData.DataBind(); } } /// <summary> /// /// </summary> /// <param name="obj"></param> /// <returns></returns> public string OutputNullable(bool nullable) { return nullable ? "<span style='font-family:宋体'>是</span>" : "<span style='font-family: 宋体; color: red'>否</span>"; } public string ColumnInfo(string tablename) { StringBuilder result = new StringBuilder(); IList<ColumnInfo> columns = provider.GetTableColumns(tablename); foreach (ColumnInfo column in columns) { result.AppendFormat(@"<tr> <td width=103 valign=top style='width:77.4pt;border:solid windowtext 1.0pt; border-top:none;padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'><span lang=EN-US>{0}</span></p> </td> <td width=84 valign=top style='width:63.0pt;border-top:none;border-left:none; border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'><span lang=EN-US>{1}</span></p> </td> <td width=51 valign=top style='width:38.25pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'><span lang=EN-US>{2}</span></p> </td> <td width=71 valign=top style='width:53.55pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'>{3}</p> </td> <td width=71 valign=top style='width:53.55pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'><span lang=EN-US>{4}</span></p> </td> <td width=95 valign=top style='width:71.3pt;border-top:none;border-left:none; border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'><span lang=EN-US>{5}</span></p> </td> <td width=92 valign=top style='width:69.05pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0cm 5.4pt 0cm 5.4pt'> <p class=MsoNormal align=center style='text-align:center'><span lang=EN-US>{6}</span></p> </td> </tr>", column.Name, column.DataType, column.Length, OutputNullable(column.Nullable), OutputValue(column.DefaultValue), OutputIdentity(column.Identity, column.IdentitySeed, column.IdentityIncrement), OutputValue(column.ColumnDesc)); } return result.ToString(); } //<span style='font-family: 宋体'>自动增长</span><span lang="EN-US">(1) </span><span style='font-family: 宋体'> // 不用于复制</span> /// <summary> /// 输出其他 /// </summary> /// <param name="obj"></param> /// <returns></returns> public string OutputIdentity(int identity, int seed, int increment) { if (identity == 1 && seed == 1 && increment == 1) return "<span style='font-family: 宋体'>自动增长</span><span lang='EN-US'>(1) </span>"; else return "&nbsp;"; } private string OutputValue(string obj) { if (string.IsNullOrEmpty(obj)) return "&nbsp;"; else return obj; } } 代码说明: 这里是嵌套输出的表格,注意处理为空的情况,否则表格可能不完整,大家可以根据实际情况进行修改。三、结果 大家直接把页面上的表格全选然后复制到Word里面即可,这里注意了,我试过直接另存为word,但是版式不对,但是直接复制到Word里面是可以的。四、下载 DB2Word2009-9-9.rar本文转自博客园农民伯伯的博客,原文链接:第100篇博文纪念 | C# 根据数据库表结构生成DOC数据库文档,如需转载请自行联系原博主。
一、MFC中使用消息队列 1.1 声明 virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); 1.2 实现 LRESULT CTestDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { return CDialog::WindowProc(message,wParam,lParam); } 本示例是继承CDialog。 二、捕获U盘插入、卸载事件 LRESULT CTestDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { //WM_DEVICECHANGE,系统硬件改变发出的系统消息 case WM_DEVICECHANGE: { PDEV_BROADCAST_HDR lpdb=(PDEV_BROADCAST_HDR)lParam; switch(wParam) { case WM_DEVICECHANGE: break; case DBT_DEVICEARRIVAL://DBT_DEVICEARRIVAL,设备检测结束,并且可以使用 { if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)//逻辑卷 { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; switch(lpdbv->dbcv_flags) { case 0: //U盘 { CString decDriver; decDriver = FirstDriveFromMask(lpdbv ->dbcv_unitmask); TRACE1("检测到U盘:[%s]插入!\n",decDriver.GetBuffer(0)); } break; case DBTF_MEDIA: //光盘 TRACE1("检测到光盘:[%c]插入!\n",FirstDriveFromMask(lpdbv ->dbcv_unitmask)); break; } } } break; case DBT_DEVICEREMOVECOMPLETE://DBT_DEVICEREMOVECOMPLETE,设备卸载或者拔出 { if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)//逻辑卷 { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; switch(lpdbv->dbcv_flags) { case 0: //U盘 { CString decDriver; decDriver = FirstDriveFromMask(lpdbv ->dbcv_unitmask); TRACE1("检测到U盘:[%s]拔出!\n",decDriver.GetBuffer(0)); } break; case DBTF_MEDIA: //光盘 break; } } } break; } } break; } return CDialog::WindowProc(message,wParam,lParam); } 三、效果图 四、文章修改 4.1 2010-5-7 MFC中使用不要使用SetWindowLong方式来获取消息队列,否则会出现无法关闭窗口的问题。 4.2 2013-2-17 感谢网友提醒,CString getBuffer后应调用ReleaseBuffer 本文转自博客园农民伯伯的博客,原文链接:[MFC]U盘检测,如需转载请自行联系原博主。
上边是一个表,下边是一些录入控件text ,select实现了:插入 ,删除,修改,读取,验证类型唯一性(每种类型只能输入一个记录) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML><HEAD><TITLE> New Document </TITLE><META NAME="Generator" CONTENT="EditPlus"><META NAME="Author" CONTENT=""><META NAME="Keywords" CONTENT=""><META NAME="Description" CONTENT=""></HEAD><script> var flg=false; var selectedColor = "#99CCCC"; var initColor = "#ffff99"; var selectedRowIndex = ""; var editObj; function add(){ var cell; var textNode; // add head var type = document.getElementsByName("type")[0]; head = type.options[type.selectedIndex].text; //check exist var hiddenHeads = document.getElementsByName("hiddenHead"); for(i=0;i<hiddenHeads.length;i++){ if(hiddenHeads[i].value == type.value){ alert("这个类型的记录已经存在"); return ; } } //add row tbl = document.getElementById("paramTbl"); rowsLen = tbl.rows.length; row = tbl.insertRow(rowsLen); //create head tag textNode = document.createTextNode(head); cell = row.insertCell(0) cell.setAttribute("hight","22"); cell.appendChild(textNode); row.appendChild(cell); //add param tag for(i=1;i<4;i++){ paramValue = document.getElementsByName("param"+i)[0].value; textNode = document.createTextNode(paramValue); cell = row.insertCell(i) cell.setAttribute("hight","22"); cell.appendChild(textNode); row.appendChild(cell); } //add head value hiddenHead = document.createElement("<input type='hidden' name='hiddenHead' value='"+type.value+"'/>"); cell = row.insertCell(4) cell.setAttribute("hight","22"); cell.appendChild(hiddenHead); row.appendChild(cell); //add param value for(i=5;i<8;i++){ paramValue = document.getElementsByName("param"+(i-4))[0].value; hidden = document.createElement("<input type='hidden' name='hiddenParam"+(i-4)+"' value='"+paramValue+"'/>"); cell = row.insertCell(i) cell.style.display='none'; cell.appendChild(hidden); row.appendChild(cell); } row.onclick=function(){rowClick(this);}; row.bgColor = initColor; init(); } function edit(){ tbl = document.getElementById("paramTbl"); if(selectedRowIndex==""){ alert("please select a row"); return ; } for(i=1;i<4;i++){ paramObj = document.getElementsByName("param"+i)[0]; hiddenObj = document.getElementsByName("hiddenParam"+i)[selectedRowIndex-1]; hiddenObj.value = paramObj.value; editObj.cells[i].innerText=paramObj.value; } init(); } function del(){ tbl = document.getElementById("paramTbl"); tbl.deleteRow(selectedRowIndex); selectedRowIndex = ""; init(); } function rowClick(obj){ tbl = document.getElementById("paramTbl"); if(selectedRowIndex != ""){ tbl.rows[selectedRowIndex].bgColor = initColor; } selectedRowIndex = obj.rowIndex; obj.bgColor = selectedColor; //reset select var type = document.getElementsByName("type")[0]; var hiddenHead = document.getElementsByName("hiddenHead")[selectedRowIndex-1]; var opts = type.options; if(flg){ alert(selectedRowIndex-1); alert(hiddenHead); alert(hiddenHead.value); } for(i=0;i<opts.length;i++){ if(opts[i].value == hiddenHead.value ){ opts[i].selected = true; } } //copy param value for(i=1;i<4;i++){ paramObj = document.getElementsByName("param"+i)[0]; hiddenObj = document.getElementsByName("hiddenParam"+i)[selectedRowIndex-1]; paramObj.value = hiddenObj.value; //alert(hiddenObj.value); } editObj=obj; } function init(){ for(i=1;i<4;i++){ param = document.getElementsByName("param"+i)[0]; param.value=""; } var type = document.getElementsByName("type")[0]; type.options[0].selected=true; } function test(){ hiddenObjs = document.getElementsByName("hiddenParam1") for(i=0;i<hiddenObjs.length;i++){ alert(hiddenObjs[i].value); } var hiddenHeads = document.getElementsByName("hiddenHead"); for(i=0;i<hiddenHeads.length;i++){ alert(hiddenHeads[i].value); } } function test2(){ if(flg){ flg=false; }else{ flg=true; } } function reset(){ tbl = document.getElementById("paramTbl"); if(selectedRowIndex!=""){ tbl.rows[selectedRowIndex].bgColor = initColor; selectedRowIndex=""; } for(i=1;i<4;i++){ param = document.getElementsByName("param"+i)[0]; param.value=""; } }</script><BODY> <div style="height:132px; width:100%; overflow-x:auto; overflow-y:auto; background-color:#ffff99;" > <table id="paramTbl" width="100%"> <tr> <td>类型</td> <td>参数1</td> <td>参数二</td> <td>参数三</td> </tr> </table> </div> <table> <tr> <td> <select name="type" onchange="reset()"> <option value="typeA">类型A</option> <option value="typeB">类型B</option> </select> </td> <td> <input type="text" name="param1"/> </td> <td> <input type="text" name="param2"/> </td> <td> <input type="text" name="param3"/> </td> </tr> <tr> <td><input type="button" onclick="add()" value="add"/></td> <td><input type="button" onclick="edit()" value="edit"/></td> <td><input type="button" onclick="del()" value="del"/></td> <td><!--<input type="button" onclick="test()" value="test"/>--></td> </tr> </table> <!--<td><input type="button" onclick="test2()" value="test2"/></td><td><input type="button" onclick="alert(selectedRowIndex)" value="test2"/></td>--></BODY></HTML> 本文转自博客园执着的笨蛋的博客,原文链接:js table 操作-----实现table的插入、修改、删除,如需转载请自行联系原博主。
1. 先贴效果图 2. 原理与功能 2.1 原理非常简单,从http://www.nod321.com/抓取最新的用户名和密码,然后更新到注册表中。 2.2 启动进入界面,直接点击"立即更新"按钮就行了,本版没有加入判断是否已经联网,所以需要你先确定自己是否能够上网!如果连续点击立即更新的话,会按上面网页中出现的升级ID从上到下依次设置为当前升级ID。 3. 部分代码 3.1 异步分析下载 /// <summary> /// 异步更新 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnUpdating_Click(object sender, EventArgs e) { AppendMessage("开始连接\r\n", Color.Blue); using (WebClient wClient = new WebClient()) { AutoResetEvent waiter = new AutoResetEvent(false); wClient.Credentials = CredentialCache.DefaultCredentials; wClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(AsyncURIAnalyze); wClient.DownloadDataAsync(new Uri(URL_USER), waiter); //waiter.WaitOne(); //阻止当前线程,直到收到信号 } } /// <summary> /// 异步分析 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void AsyncURIAnalyze(Object sender, DownloadDataCompletedEventArgs e) { //消息 AppendMessage("已连接,正在分析\r\n", Color.Blue); //获取数据 string pageData = Encoding.UTF8.GetString(e.Result); MatchCollection matchs = Regex.Matches(pageData, REGULAR_USER, RegexOptions.IgnoreCase); foreach (Match match in matchs) { string[] values = match.Value.Replace("<br/>", "@").Split('@'); string username = values[0].Replace("UserName:", string.Empty).Trim(); string password = values[1].Replace("PassWord:", string.Empty).Trim(); if (!users.Contains(username)) { users.Add(username); Regedit(username,password); break; } } } 3.2 Nod32的密码加密与解密 /// <summary> /// 解密 /// </summary> /// <param name="buf"></param> /// <returns></returns> private string byte2str(byte[] buf) { StringBuilder pwd = new StringBuilder(); if (buf != null) { for (int i = 0, j = mask.Length; i < j; i += 2) { pwd.Append((char)(buf[i] ^ mask[i])); } } return pwd.ToString(); } /// <summary> /// 加密 /// </summary> /// <param name="str"></param> /// <returns></returns> private byte[] str2byte(string str) { byte[] buf = Encoding.ASCII.GetBytes(str); byte[] result = new byte[buf.Length * 2]; if (buf != null) { for (int i = 0, j = 0; i < mask.Length; i++, j++) { result[i] = (byte)(buf[j] ^ mask[i]); result[++i] = mask[i]; } } return result; } 4. 下载 4.1 安装程序 NodFixSetup.rar 解压安装即可。 4.2 可直接运行的EXE文件,需要Framework 2.0 NodFix.rar 4.3 源代码 NodFixSrc.rar 5. 注意 由于http://www.nod321.com/更新升级ID稍慢导致ID无效,需要你重复点击"立即更新"来尝试其他的升级ID,如果本程序更新的ID都无法使用,也代表上面这个网站的升级ID无法使用!比如2009-5-15更新的升级ID中只有最后一组可以使用! 后期维护 1. 2009-7-20 修正两个BUG,分别是密码为空是更新出错和匹配用户名密码没考虑Username和Password这种情况,更新exe下载,替换NodFix.exe就行: NodFix2009-7-20.rar 2. 2009-8-3 紧急修正分析结果未加Tirm()的BUG,同上,替换NodFix.exe就行: NodFix2009-8-3.rar 3. 2009-9-4 由于nod321.com网站被关闭,在本软件失效之际找到另外一个提供免费升级ID的网站:nod320.org,小有改动代码,请下载替换NodFix.exe: NodFix2009-9-4.rar 4. 2009-9-20 nod320.org改了匹配的用户名 - -#,请替换NodFix.exe,也附加本次的源代码,自己用闲工夫的人把这个程序改成一个字典形式的吧,我懒 - - #。 EXE: NodFix2009-9-20_EXE.rar SRC: NodFix2009-9-20_SRC.rar 5. 2011-3-25 已经购买正版360版ESET NOD32,40元一年。上班已经4年,能承受得起这个费用了,支持正版!本文源代码要是觉得有价值可以下载学习一下,主要是操作注册表。 本文转自博客园农民伯伯的博客,原文链接:NOD32升级账号更新器 [ C# | NOD32 | Eset ],如需转载请自行联系原博主。
一、目的 从数据库导出数据到Excel中并锁定部分数据不让修改。这里以学生成绩表为例, 学生编号、学生姓名、学生成绩 三个字段从数据库提取,并锁定,老师评价栏在导出后可输入。 二、实现 1. 制作Excel"模板" 注意这里的模板不是指excel里面的模板,主要为后面导出成html做准备。 1.1 新建Excel,名称为学生成绩表.xls 。 1.2 设置列名栏目,设置格式字体等信息,最终形式的格式,如图: 冻结窗口的方法:比如要冻结第一行,选择第二行的第一个单元格,工具栏->窗口->冻结窗口。 1.3 锁定区域 1.3.1 Excel全选->右键 设置单元格格式->保护->去掉 锁定 前复选框 1.3.2 选择学生编号、学生姓名、学生成绩这三列,同上(1.3.1)步骤相反,即勾上 锁定 前的复选框。 1.3.3 输入测试数据 1 张三 83。 1.3.4 工具->保护->保护工作表,模板完成!如果你在锁定后再更改前面三列,将出现如下警告框: 2. 导出Excel为html格式并复制到一个空白的aspx页面中 2.1 工具栏 文件->另存为网页,导出后的文件为学生成绩表.htm。 2.2 用记事本或UE打开,可以看到如下部分代码: <html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=gb2312"><meta name=ProgId content=Excel.Sheet><meta name=Generator content="Microsoft Excel 11"><link rel=File-List href="学生成绩表.files/filelist.xml"><link rel=Edit-Time-Data href="学生成绩表.files/editdata.mso"><link rel=OLE-Object-Data href="学生成绩表.files/oledata.mso"><!--[if gte mso 9]><xml> <o:DocumentProperties> <o:Created>1996-12-17T01:32:42Z</o:Created> <o:LastSaved>2009-05-25T06:35:53Z</o:LastSaved> 2.3 新建aspx页面: Export.aspx。 2.4 去掉Export.aspx中除<%@ Page 的代码,复制htm里面的代码到空白的Export.aspx中,添加<form id="form1" runat="server">。 3. 调取数据并显示 3.1 找到测试数据部分的html代码替换为asp:Repeater控件代码,如下 <!-- <tr height=19 style='height:14.25pt'> <td height=19 class=xl27 style='height:14.25pt' x:num>1</td> <td class=xl27>张三</td> <td class=xl27 x:num>83</td> <td class=xl25></td> </tr> --> <asp:Repeater ID="rptData" runat="server"> <HeaderTemplate> </HeaderTemplate> <ItemTemplate> <tr height=19 style='height:14.25pt'> <td height=19 class=xl27 style='height:14.25pt' x:num> <%#Eval("id")%> </td> <td class=xl27> <%#Eval("name")%> </td> <td class=xl27 x:num> <%#Eval("achievement")%> </td> <td class=xl25></td> </tr> </ItemTemplate> <FooterTemplate> </FooterTemplate></asp:Repeater> 3.2 后台调取数据,导成excel并下载 这里就不连接数据库了,直接在程序里面模拟一些数据。 protected void Page_Load(object sender, EventArgs e) { this.EnableViewState = false; //加载数据 LoadData(); Response.Clear(); Response.Buffer = true; Response.Charset = "GB2312"; Response.AppendHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode("学生成绩表.xls", System.Text.Encoding.UTF8)); Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312"); Response.ContentType = "application/ms-excel"; //Response.End(); } private void LoadData() { IList<User> users = new List<User>(); //测试数据 users.Add(new User(1, "刘一", 81)); users.Add(new User(2, "陈二", 82)); users.Add(new User(3, "张三", 83)); users.Add(new User(4, "李四", 84)); users.Add(new User(5, "王五", 85)); users.Add(new User(6, "赵六", 86)); users.Add(new User(7, "孙七", 87)); users.Add(new User(8, "周八", 88)); users.Add(new User(9, "吴九", 89)); users.Add(new User(10, "郑十", 80)); rptData.DataSource = users; rptData.DataBind(); } [Serializable] private class User { public User() { } public User(int id, string name, decimal achievement) { this._id = id; this._name = name; this._achievement = achievement; } private int _id; /// <summary> /// 编号 /// </summary> public int id { get { return _id; } set { _id = value; } } private string _name; /// <summary> /// 姓名 /// </summary> public string name { get { return _name; } set { _name = value; } } private decimal _achievement; /// <summary> /// 成绩 /// </summary> public decimal achievement { get { return _achievement; } set { _achievement = value; } } } 代码说明: Page_Load中依次加载数据,然后以ms-excel类型讲web浏览变成excel文件下载。 3.3 导出后的excel截图 3.3.1 下载 3.3.2 修改锁定的三列截图 很明显,动态输出表格是我们擅长的,也不用你去翻N多N多的API了,最重要的是这里没有Excel进程! 三、下载 1. 源代码2009-5-25 四、注意 1. 下载回来的excel如果直接在上面操作的话可能产生 [excel名称].files 文件夹。 本文转自博客园农民伯伯的博客,原文链接:C# 操作Excel之旁门左道 [ C# | Excel ],如需转载请自行联系原博主。
我在开发中经常用到的mysql命令和脚本,以作备用,最近有段时间没写sql了,有点生疏了。 (以下是在winxp下开发的,打开命令提示符)。 第一招、mysql服务的启动和停止 net stop mysql net start mysql 第二招、登陆mysql 语法是 mysql -h主机 -u用户名 -p秘密 例子是 mysql -hlocalhost -uroot -p123456 要确定mysql安装时候勾选了可以远程链接。如果登陆本地计算机,-h可以省略,键入命令mysql -uroot -p, 回车后提示你输入密码,输入123456,然后回车即可进入到mysql中了。 第三招、增加新用户 语法是 grant 权限 on 数据库.表 to 用户名@登录主机 identified by “密码” 例子是 所有权限 grant all privalleges on zf.* to guqin@localhost identified by “123456″ select权限 grant all select on zf.* to guqin@localhost identified by “123456″ 第四招、操作数据库 登录到mysql中,然后在mysql的提示符下运行下列命令,每个命令以分号结束。 1、 显示数据库列表。 show databases; 2、 显示库中的数据表。 use mysql; show tables; 3、 显示数据表的结构。 desc 表明; 4、 建库与删库 create database 库名; drop database 库名; 5、 建表和删表。 use 库名; create table 表名(字段列表); drop table 表名; 6、 清空表中记录。 delete from 表名; 7、 显示表中的记录。 select * from 表名; 第五招、导出和导入数据 1. 导出数据。 语法是 mysqldump –opt 库名.表名 > c:\data.sql 例子是 mysqldump -hlocalhost -uroot -p123456 zf.user>c:\data.sql 2. 导入数据: 语法是 mysqldump –opt 库名 < c:\data.sql 例子是 mysqldump -hlocalhost -uroot -p123456 zf 或者 mysqlimport -hlocalhost -u root -p123456 < c:\data.sql 3. 将文本数据导入数据库: use 库名; load data local infile “文件名” into table 表名; 第六招 创建一个数据库表 CREATE TABLE MYTABLE (name VARCHAR(20), sex CHAR(1)); 第七招 往表中加入记录 insert into 表名 values (”1″,”2″); 第八招 用文本方式将数据装入数据库表中 LOAD DATA LOCAL INFILE “c:/data.sql” INTO TABLE 表名; 第九招 导入.sql文件命令(例如c:/data.sql) use database; source c:/data.sql 第十招 更新表中数据 update MYTABLE set sex=”f” where name=’hyq’; 第十一招 修复表 repair 表名 第十二招 查看表的大小 show 表名 status 第十三招 修改密码 mysqladmin -u用户名 -p旧密码 password “新密码” 第十四招 修改表结构 ALTER TABLE t1 MODIFY b BIGINT NOT NULL; 第十四招 退出MYSQL命令 exit or quit(回车) 以上是我的mysql操作命令,很方便。自己感觉比用gui操作好多了。 本文转自博客园沉睡森林@漂在北京的博客,原文链接:mysql命令,如需转载请自行联系原博主。
MySQL主要配置文件位置:/etc/mysql/my.cnf.数据库表文件夹:/var/lib/mysql/,相当于Windows下MySQL的date文件夹登录MySQL,执行编码显示:show variables like 'character%';QUOTE: +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 修改MySQL默认数据库的编码需要编辑my.cnf文件,Windows可以直接用Mysql Server Instance Config Wizard 进行设置sudo gedit /etc/mysql/my.cnf找到[client] 添加:default-character-set=utf8 //默认字符集为utf8找到[mysqld] 添加:QUOTE: //默认字符集为utf8 default-character-set=utf8 //设定连接mysql数据库时使用utf8编码,以让mysql数据库为utf8运行 init_connect='SET NAMES utf8' 修改好后,重新启动mysql 即可.查询一下show variables like 'character%';QUOTE: +--------------------------+----------------------------+| Variable_name | Value |+--------------------------+----------------------------+| character_set_client | utf8 || character_set_connection | utf8 || character_set_database | utf8 || character_set_filesystem | binary || character_set_results | utf8 || character_set_server | utf8 || character_set_system | utf8 || character_sets_dir | /usr/share/mysql/charsets/ |+--------------------------+----------------------------+ 本文转自博客园沉睡森林@漂在北京的博客,原文链接:Ubuntu修改mysql的编码集,如需转载请自行联系原博主。
很久以前没有出现过乱码的问题了,最近却发现有乱码的问题,麻烦。baidu了一下,发现在tomcat的/conf/server.xml里面修改一下配置即可。 <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="UTF-8" redirectPort="8443" /> 本文转自博客园沉睡森林@漂在北京的博客,原文链接:tomcat乱码的问题,如需转载请自行联系原博主。
下载sqldeveloper_2.1.0.63.73-2_all.deb 然后解压缩到当前文件下,拷贝到目标文件夹下面。 找到/home/wangbing/ProgramData/sqldeveloper-2.1.0.63.73-1.noarch/opt/sqldeveloper这个目录下的文件 运行sqldeveloper.sh文件即可 前提是安装了JDK 本文转自博客园沉睡森林@漂在北京的博客,原文链接:ubuntu下oracle的客户端安装,如需转载请自行联系原博主。
下面的代码定义了一个完整的ext treepanel的实例,其中,对checkchange事件的处理,使单击父亲节点时对下面的子节点全部选中或取消选中。 sysFunClassTree = new Ext.tree.TreePanel({ id:'sysFunClassTree',split:true,collapsible:true,rootVisible:false,name:'sysFunClassTree',autoScroll:true,border:true, region:'east',title:'功能分类树',width:200, loader:new Ext.tree.TreeLoader({dataUrl:'http://localhost:8080/jeasyweb/treeSysFunClass.do',baseParams:{'_tree_checkbox':'true'}})}); sysFunClassTree_root = new Ext.tree.AsyncTreeNode({ text:'Ext TreeRoot',id:'src_root' }); sysFunClassTree.setRootNode(sysFunClassTree_root); sysFunClassTree.on('click', function(node, e){treeClick(node, e);}); sysFunClassTree.on('checkchange', function(node, flag) { if (node.hasChildNodes()) { node.eachChild(function(child) { child.ui.toggleCheck(flag); child.attributes.checked = flag; child.fireEvent('checkchange', child, flag); }); } }); 本文转自博客园沉睡森林@漂在北京的博客,原文链接:带checkbox的treepanel实例,如需转载请自行联系原博主。
ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。 ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。 线程局部变量并不是Java的新发明,很多语言(如IBM IBM XL FORTRAN)在语法层面就提供线程局部变量。在Java中没有提供在语言级支持,而是变相地通过ThreadLocal的类提供支持。 所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。 ThreadLocal的接口方法 ThreadLocal类接口很简单,只有4个方法,我们先来了解一下: void set(Object value) 设置当前线程的线程局部变量的值。 public Object get() 该方法返回当前线程所对应的线程局部变量。 public void remove() 将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。 protected Object initialValue() 返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。 值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。 ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。我们自己就可以提供一个简单的实现版本: 代码清单1 SimpleThreadLocal public class SimpleThreadLocal { private Map valueMap = Collections.synchronizedMap(new HashMap()); public void set(Object newValue) { valueMap.put(Thread.currentThread(), newValue);①键为线程对象,值为本线程的变量副本 } public Object get() { Thread currentThread = Thread.currentThread(); Object o = valueMap.get(currentThread);②返回本线程对应的变量 if (o == null && !valueMap.containsKey(currentThread)) {③如果在Map中不存在,放到Map 中保存起来。 o = initialValue(); valueMap.put(currentThread, o); } return o; } public void remove() { valueMap.remove(Thread.currentThread()); } public Object initialValue() { return null; } } 虽然代码清单9‑3这个ThreadLocal实现版本显得比较幼稚,但它和JDK所提供的ThreadLocal类在实现思路上是相近的。 一个TheadLocal实例 下面,我们通过一个具体的实例了解一下ThreadLocal的具体使用方法。 代码清单2 SequenceNumber package com.baobaotao.basic; public class SequenceNumber { ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值 private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){ public Integer initialValue(){ return 0; } }; ②获取下一个序列值 public int getNextNum(){ seqNum.set(seqNum.get()+1); return seqNum.get(); } public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); ③ 3个线程共享sn,各自产生序列号 TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn) { this.sn = sn; } public void run() { for (int i = 0; i < 3; i++) {④每个线程打出3个序列值 System.out.println("thread["+Thread.currentThread().getName()+ "] sn["+sn.getNextNum()+"]"); } } } } 通常我们通过匿名内部类的方式定义ThreadLocal的子类,提供初始的变量值,如例子中①处所示。TestClient线程产生一组序列号,在③处,我们生成3个TestClient,它们共享同一个SequenceNumber实例。运行以上代码,在控制台上输出以下的结果: thread[Thread-2] sn[1] thread[Thread-0] sn[1] thread[Thread-1] sn[1] thread[Thread-2] sn[2] thread[Thread-0] sn[2] thread[Thread-1] sn[2] thread[Thread-2] sn[3] thread[Thread-0] sn[3] thread[Thread-1] sn[3] 考察输出的结果信息,我们发现每个线程所产生的序号虽然都共享同一个SequenceNumber实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。 Thread同步机制的比较 ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。 而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。 由于ThreadLocal中可以持有任何类型的对象,低版本JDK所提供的get()返回的是Object对象,需要强制类型转换。但JDK 5.0通过泛型很好的解决了这个问题,在一定程度地简化ThreadLocal的使用,代码清单 9 2就使用了JDK 5.0新的ThreadLocal<T>版本。 概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。 Spring使用ThreadLocal解决线程安全问题 我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。 一般的Web应用划分为展现层、服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用。在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程,如图9‑2所示: 图1同一线程贯通三层 这样你就可以根据需要,将一些非线程安全的变量以ThreadLocal存放,在同一次请求响应的调用线程中,所有关联的对象引用到的都是同一个变量。 下面的实例能够体现Spring对有状态Bean的改造思路: 代码清单3 TopicDao:非线程安全 public class TopicDao { private Connection conn;①一个非线程安全的变量 public void addTopic(){ Statement stat = conn.createStatement();②引用非线程安全变量 … } } 由于①处的conn是成员变量,因为addTopic()方法是非线程安全的,必须在使用时创建一个新TopicDao实例(非singleton)。下面使用ThreadLocal对conn这个非线程安全的“状态”进行改造: 代码清单4 TopicDao:线程安全 import java.sql.Connection; import java.sql.Statement; public class TopicDao { ①使用ThreadLocal保存Connection变量 private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>(); public static Connection getConnection(){ ②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection, 并将其保存到线程本地变量中。 if (connThreadLocal.get() == null) { Connection conn = ConnectionManager.getConnection(); connThreadLocal.set(conn); return conn; }else{ return connThreadLocal.get();③直接返回线程本地变量 } } public void addTopic() { ④从ThreadLocal中获取线程对应的Connection Statement stat = getConnection().createStatement(); } } 不同的线程在使用TopicDao时,先判断connThreadLocal.get()是否是null,如果是null,则说明当前线程还没有对应的Connection对象,这时创建一个Connection对象并添加到本地线程变量中;如果不为null,则说明当前的线程已经拥有了Connection对象,直接使用就可以了。这样,就保证了不同的线程使用线程相关的Connection,而不会使用其它线程的Connection。因此,这个TopicDao就可以做到singleton共享了。 当然,这个例子本身很粗糙,将Connection的ThreadLocal直接放在DAO只能做到本DAO的多个方法共享Connection时不发生线程安全问题,但无法和其它DAO共用同一个Connection,要做到同一事务多DAO共享同一Connection,必须在一个共同的外部类使用ThreadLocal保存Connection。 小结 ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。 本文转自博客园沉睡森林@漂在北京的博客,原文链接:[转]理解ThreadLocal,如需转载请自行联系原博主。
Java算法——判断素数 public static boolean isPrimeNumber(int number){ if(number<2) return false; for(int i=2;i<=Math.sqrt(number);i++){ if(number%i==0&&number!=2) return false; } return true; } 素数算法(二) 上次讨论了简单的素数判定的算法,不过这个算法对于位数较大(一般小于108)的素数判定就显得相当力不从心了。比如在素数目前最广泛的应用领域-公共密钥体系中,一般选择的素数都是相当大的(通常在100位以上),如果采用上次的试除法来判定,那么可能要穷尽你一生的时间都还不够。所以在一般的应用领域,人们采用的是Rabin-Miller检验法。下面是该检验法的算法: 首先选择一个代测的随机数p,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。 (1) 选择一个小于p的随机数a。 (2) 设j=0且z=a^m mod p (3) 如果z=1或z=p-1,那麽p通过测试,可能使素数 (4) 如果j>0且z=1, 那麽p不是素数 (5) 设j=j+1。如果j<b且z<>p-1,设z=z^2 mod p,然后回到(4)。如果z=p-1,那麽p通过测试,可能为素数。 (6) 如果j=b 且z<>p-1,不是素数 数a被当成证据的概率为75%。这意味着当迭代次数为t时,它产生一个假的素数所花费的时间不超过1/4^t。实际上,对大多数随机数,几乎99.99%肯定a是证据。 实际考虑: 在实际算法,产生素数是很快的。 (1) 产生一个n-位的随机数p (2) 设高位和低位为1(设高位是为了保证位数,设低位是为了保证位奇数) (3) 检查以确保p不能被任何小素数整除:如3,5,7,11等等。有效的方法是测试小于2000的素数。使用字轮方法更快 (4) 对某随机数a运行Rabin-Miller检测,如果p通过,则另外产生一个随机数a,在测试。选取较小的a值,以保证速度。做5次 Rabin-Miller测试如果p在其中失败,从新产生p,再测试。 经测试,这个算法在sun的Sparc II工作站上实现: 2 .8秒产生一个256位的素数 24.0秒产生一个512位的素数 2分钟产生一个768位的素数 5.1分钟产生一个1024位的素数 最近在网上看了不少关于素数的问题,也学习到了不少东西,决定整理一下,算是一个学习的总结吧。 首先想说明的是,虽然素数可以进行很深入的研究(如在RSA公共密钥系统的应用),但是由于我对数论的不甚熟悉,所以只能做一些浅尝辄止的探讨,主要就是对一些简单的素数相关算法进行一个讨论。 首先来说说素数的判定算法,如果你是读谭浩强老师的《c程序设计》入门的话,那么一谈到素数的判定算法,你首先应该想到的就是以下的算法:给定一个正整数n,用2到sqrt(n)之间的所有整数去除n,如果可以整除,则n不是素数,如果不可以整除,则n就是素数。这个算法的时间复杂度十分明了,为O(sqrt(n)),算法的描述相当简单,实现也一样不困难。 # include <stdio.h> # include <math.h> int isPrime(int n) { int i ; for(i=2; i <= sqrt(n); i++){ if(n%i == 0 ) break ; } if(i <= sqrt(n)) printf("%d is not a prime ! ", &n) ; else printf("%d is a prime ! ", &n) ; return 0 ; } ===================================== public class SuShu{ private int num; SuShu(int n){ num=n; } public boolean isSuShu(){ for(int i=2;i<num;i++){ if(num%i==0) return false; } return true; } public static void main(String[] args){ for(int i=1;i<=100;i++){ SuShu su=new SuShu(i); if(su.isSuShu()) System.out.println(i+"是素数"); else System.out.println(i+"不是素数"); } } } ============================= /** * @param n * @return if n is a prime return true, else false */ public static boolean isPrime(int n) { // filte negative, zero, one if (1 >= n) { return false; } // 2 is a prime, stop filter if (2 == n) { return true; } // filter evens if (0 == n % 2) { return false; } // go on filting... for (int a = 3; a <= Math.sqrt(n); a += 2) { if (0 == n % a) { return false; } } // the rest is all prime, stop filting return true; } ============================== //目前我认为最好的办法是:(不是lk的观点)public boolean isPrime(int n){ for(int i = 2; i * i <= n; i++){ if(n % i == 0) return false; } return true; } =============================== 素数是这样的整数,它除了能表示为它自己和1的乘积以外,不能表示为任何其它两个整数的乘积。例如,15=3*5,所以15不是素数;又如,12=6*2=4*3,所以12也不是素数。另一方面,13除了等于13*1以外,不能表示为其它任何两个整数的乘积,所以13是一个素数。 有的数,如果单凭印象去捉摸,是无法确定它到底是不是素数的。有些数则可以马上说出它不是素数。一个数,不管它有多大,只要它的个位数是2、4、5、6、8或0,就不可能是素数。此外,一个数的各位数字之和要是可以被3整除的话,它也不可能是素数。但如果它的个位数是1、3、7或9,而且它的各位数字之和不能被3整除,那么,它就可能是素数(但也可能不是素数)。没有任何现成的公式可以告诉你一个数到底是不是素数。你只能试试看能不能将这 个数表示为两个比它小的数的乘积。 代码如下: package com.vo; public class Sushu { public static void main(String[] args) { int s=0; int i; for(i=0;i<=100;i++) { int j; for(j=2;j<=i;j++){ if(i%j==0) break; } if(i==j) System.out.println(i); } } } 本文转自博客园执着的笨蛋的博客,原文链接:素数算法(小汇),如需转载请自行联系原博主。
1.下载linux版本的myeclipse8文件myeclipse-8.0.0-linux-gtk-x86.tgz,具体地址baidu一下就可以找到了。2.安装过程中按钮死话不能点,后来不停的按enter键居然安装成功了。3.安好后还是出现按钮不能使用的问题,baidu了半天找到了发现需要额外的加入一个sh文件。具体内容如下:export GDK_NATIVE_WINDOWS=true /home/wangbing/Genuitec/"MyEclipse 8.x Latest"/myeclipse发现有空格,终端不能使用,后来又baidu得到如下结果: 1.修改文件夹名。你已经做了。2.命令这样写:cd My“ ”Pictures3.重写cd命令函数,使它能直接识别中间有空格的路径名。当然这不是一般人能做的!反正我就不会。 本文转自博客园沉睡森林@漂在北京的博客,原文链接:在Ubuntu下安装myclipse8.0GA的痛苦过程,如需转载请自行联系原博主。
/** * *问题或许可以是这样:产生m个随机正整数,要求范围是从1到n,平且它们互不相同。 问题或许可以这样解决: 假设我们已经有了经过排序的(升序),且满足要求的k个正整数,我们继续: 1、在从1到n-k的区间范围内,产生一个随机的正整数i1; 2、统计在已有序列中比i1小的数,将其个数加到i1上,得到i2;再统计从i1到i2数的个数,得到i3;一直循环,直到i不变为止。然后,把i插入已有的序列。这个过程相当于从头数出i1个空白,以此来保证新的数是随机的。 3、这时得到了k+1个满足要求的数,然后就循环吧。 上面的方法适用于n很大,但是m很小的时候。 如果m和n都很大,并且希望一次性的产生,那么: 1先产生有一定冗余的随机正整数,然后排序,然后去掉相同的数。 如果,产生了超额的数,可以将数列再打乱顺序,然后,取出符合规定的数目的数。 当然,也可以两种方法相结合,就是: 1、先产生超过需求的、有一定冗余的随机正整数,然后排序,然后去掉相同的数,并且保存下来。记录它的数目m1 >m; 2、当要用时,在产生一个从1到m的随机数j,然后取出数据库中第j个数,输出,并且把它从数据库中删除到。 * * * * * * * * *数据有点大,用了128m start_1 (); 是即时输出(因为用boolean数组,所以内存小得多) start_2 (); 是把数据存进数组,以便再处理(需要内存很大,不赞成使用) 如果要处理数据,可以用 start_1 (); 把数据保存进文件,再从文件中读取数据进行处理。 */ public class Main{ public final int n = 10000000; public Main () { start_1(); //start_2 (); } public static void main (String[] args) { new Main(); } public void start_1() { //布朗型默认为 false boolean[] barr = new boolean[n]; // java.util.Random r = new java.util.Random (); int j = 0, x; int m = n; while(j < m) { x = r.nextInt (n); if (! barr[x]) { j++; barr[x] = true; System.out.println (x); } } } public void start_2() { //整型默认为 0 int[] iarr = new int[n]; // java.util.Random r = new java.util.Random (); int j = 0, x; int m = n; //少循环一次,因为要生成 0 while(j < m-1) { x = r.nextInt (n); if (iarr[x] == 0) { j++; iarr[x] = j; } } } } /* *上面的算法,没有优化,生成数据耗时间。 下面的算法改进了一下。生成所有数据半分钟左右。 +---------- | 0...999999 | . | . | . | 99 Java code public class Main { public Main () { start_1 (); start_2 (); } public static void main (String[] args) { new Main (); } ** void start_1 () { for (int i = 0; i < n; i++) { byte j = 0; while(j < m-1) { int x = r.nextInt (m); if (barr_1[x] == 0) { j++; barr_1[x] = j; } } } } ** void start_2 () { int j = 0; while(j < n) { int x = r.nextInt (n); int y = (int) barr_2[x]; if (y < m) { j++; barr_2[x]++; int z = ((int) barr_1[x][y]) * n; //System.out.println (x + z); } } } ** final int s = 10000*10000; ** final int m = 100; ** final int n = s/m; ** byte[][] barr_1 = new byte[n][m]; ** byte[] barr_2 = new byte[n]; ** java.util.Random r = new java.util.Random (); } */ /* *和一位仁兄在另一个帖子争论中,受到启发。 终于悟出一种时间复杂度极低的算法。 (可以证明,任意一个数 在 任意位置的概率 都为 1/n) 因为内存不够,所以改成了7个9来算。总时间2秒 Java code public class Main { public Main () { start (); } public static void main (String args[]) { new Main (); } ** void start () { java.util.Random r = new java.util.Random (); for (int i = 0; i < n; i++) { int x = r.nextInt (i+1); iarr = iarr[x]; iarr[x] = i; } // int m = 10; for (int i = 0; i < m; i++) { System.out.print (iarr + " "); } } ** final int n = 1000*10000; ** int[] iarr = new int[n]; } */ 本文转自博客园执着的笨蛋的博客,原文链接:java 乱序(小汇),如需转载请自行联系原博主。
如何建立索引 · 索引通常被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度。所以我们选择索引的列也通常选择出现在WHERE子句、join子句、ORDER BY或GROUP BY子句中的列。 · 选择索引时,需要考虑数据列的基数。所谓基数,是指数据列所包含的不同的数据的个数。如果基数相对于数据表行数较高的话,索引的效果比较好。换句话说,就是指数据列的不同的值越多,索引效果越好。如果一个数据列只包含:0或者1两个值的话,索引的用处就不大。如果值出现的几率几乎相等,那么无论搜索哪个值都可能得到一半的数据行。在这些情况下,最好根本不要使用索引。 · 索引值较短的值,所选择的数据类型也尽可能的要小一些。譬如:如果TEXT能满足需求的话,我们就不需要用MEDIUTEXT。 · 如果建立联合索引的话,譬如对:t1,t2,t3建立联合索引的话,同时也是对t1和t1,t2建立了索引。但是如果单独指定t2、t3、t1t3、t2t3的值的话,都会用不到索引。 sql语句中如何避免没有使用索引的情况 首先先了解一下mysql优化器的工作原理:MySQL查询优化器最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行。所以当我们提交查询语句时,如果优化器排除不符合条件的数据的速度越快,那么查询的结果也会越快。 ·尽量比较数据类型相同的数据列。例如,INT与BIGINT是不同的。CHAR(10)被认为是CHAR(10)或VARCHAR(10),但是与CHAR(12)或VARCHAR(12)不同。 ·尽量不要在where子句中对索引列使用表达式或者函数。如果你在索引列使用函数调用或者更复杂的算术表达式,MySQL就不会使用索引,因为它必须计算出每个数据行的表达式值。 WHERE mycol < 4 / 2 使用索引 WHERE mycol * 2 < 4 没有使用索引 · 在使用LIKE时,尽量不要在开头使用通配符。 WHERE col_name LIKE ’%string%’ WHERE col_name LIKE ’abc%’ · 不要使用类型转换。如果某个索引列是int型,而在查询时,赋值为字符型,将使用不了索引。 SELECT * FROM mytbl WHERE num_col = 1;使用索引 SELECT * FROM mytbl WHERE num_col = ‘1’;没有使用索引 ·在SELECT语句中可以使用STRAIGHT_JOIN关键字来重载优化器的选择。 SELECT STRAIGHT_JOIN ... FROM t1, t2, t3 ... ; SELECT ... FROM t1 STRAIGHT_JOIN t2 STRAIGHT_JOIN t3 ... ; 本文转自博客园执着的笨蛋的博客,原文链接:MYSQL使用索引的方法,如需转载请自行联系原博主。
[精华] md5算法的java源代码! http://www.chinaunix.net 作者:ii 发表于:2003-08-19 02:57:15 public class MD5 { /* * A Java implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as defined in RFC 1321. * Based on the JavaScript implementation of Paul Johnston * Copyright (C) Paul Johnston 1999 - 2000. * See http://pajhome.org.uk/site/legal.html for details. * Java Version by Thomas Weber (Orange Interactive GmbH) */ /* * Convert a 32-bit number to a hex string with ls-byte first */ String hex_chr = "0123456789abcdef"; private String rhex(int num) { String str = ""; for(int j = 0; j <= 3; j++) str = str + hex_chr.charAt((num >;>; (j * 8 + 4)) &amp; 0x0F) + hex_chr.charAt((num >;>; (j * 8)) &amp; 0x0F); return str; } /* * Convert a string to a sequence of 16-word blocks, stored as an array. * Append padding bits and the length, as described in the MD5 standard. */ private int[] str2blks_MD5(String str) { int nblk = ((str.length() + 8) >;>; 6) + 1; int[] blks = new int[nblk * 16]; int i = 0; for(i = 0; i < nblk * 16; i++) { blks = 0; } for(i = 0; i < str.length(); i++) { blks[i >;>; 2] |= str.charAt(i) << ((i % 4) * 8); } blks[i >;>; 2] |= 0x80 << ((i % 4) * 8); blks[nblk * 16 - 2] = str.length()*8; return blks; } /* * Add integers, wrapping at 2^32 */ private int add(int x, int y) { return ((x&amp;0x7FFFFFFF) + (y&amp;0x7FFFFFFF)) ^ (x&amp;0x80000000) ^ (y&amp;0x80000000); } /* * Bitwise rotate a 32-bit number to the left */ private int rol(int num, int cnt) { return (num << cnt) | (num >;>;>; (32 - cnt)); } /* * These functions implement the basic operation for each round of the * algorithm. */ private int cmn(int q, int a, int b, int x, int s, int t) { return add(rol(add(add(a, q), add(x, t)), s), b); } private int ff(int a, int b, int c, int d, int x, int s, int t) { return cmn((b &amp; c) | ((~b) &amp; d), a, b, x, s, t); } private int gg(int a, int b, int c, int d, int x, int s, int t) { return cmn((b &amp; d) | (c &amp; (~d)), a, b, x, s, t); } private int hh(int a, int b, int c, int d, int x, int s, int t) { return cmn(b ^ c ^ d, a, b, x, s, t); } private int ii(int a, int b, int c, int d, int x, int s, int t) { return cmn(c ^ (b | (~d)), a, b, x, s, t); } /* * Take a string and return the hex representation of its MD5. */ public String calcMD5(String str) { int[] x = str2blks_MD5(str); int a = 0x67452301; int b = 0xEFCDAB89; int c = 0x98BADCFE; int d = 0x10325476; for(int i = 0; i < x.length; i += 16) { int olda = a; int oldb = b; int oldc = c; int oldd = d; a = ff(a, b, c, d, x[i+ 0], 7 , 0xD76AA478); d = ff(d, a, b, c, x[i+ 1], 12, 0xE8C7B756); c = ff(c, d, a, b, x[i+ 2], 17, 0x242070DB); b = ff(b, c, d, a, x[i+ 3], 22, 0xC1BDCEEE); a = ff(a, b, c, d, x[i+ 4], 7 , 0xF57C0FAF); d = ff(d, a, b, c, x[i+ 5], 12, 0x4787C62A); c = ff(c, d, a, b, x[i+ 6], 17, 0xA8304613); b = ff(b, c, d, a, x[i+ 7], 22, 0xFD469501); a = ff(a, b, c, d, x[i+ 8], 7 , 0x698098D8); d = ff(d, a, b, c, x[i+ 9], 12, 0x8B44F7AF); c = ff(c, d, a, b, x[i+10], 17, 0xFFFF5BB1); b = ff(b, c, d, a, x[i+11], 22, 0x895CD7BE); a = ff(a, b, c, d, x[i+12], 7 , 0x6B901122); d = ff(d, a, b, c, x[i+13], 12, 0xFD987193); c = ff(c, d, a, b, x[i+14], 17, 0xA679438E); b = ff(b, c, d, a, x[i+15], 22, 0x49B40821); a = gg(a, b, c, d, x[i+ 1], 5 , 0xF61E2562); d = gg(d, a, b, c, x[i+ 6], 9 , 0xC040B340); c = gg(c, d, a, b, x[i+11], 14, 0x265E5A51); b = gg(b, c, d, a, x[i+ 0], 20, 0xE9B6C7AA); a = gg(a, b, c, d, x[i+ 5], 5 , 0xD62F105D); d = gg(d, a, b, c, x[i+10], 9 , 0x02441453); c = gg(c, d, a, b, x[i+15], 14, 0xD8A1E681); b = gg(b, c, d, a, x[i+ 4], 20, 0xE7D3FBC8); a = gg(a, b, c, d, x[i+ 9], 5 , 0x21E1CDE6); d = gg(d, a, b, c, x[i+14], 9 , 0xC33707D6); c = gg(c, d, a, b, x[i+ 3], 14, 0xF4D50D87); b = gg(b, c, d, a, x[i+ 8], 20, 0x455A14ED); a = gg(a, b, c, d, x[i+13], 5 , 0xA9E3E905); d = gg(d, a, b, c, x[i+ 2], 9 , 0xFCEFA3F8); c = gg(c, d, a, b, x[i+ 7], 14, 0x676F02D9); b = gg(b, c, d, a, x[i+12], 20, 0x8D2A4C8A); a = hh(a, b, c, d, x[i+ 5], 4 , 0xFFFA3942); d = hh(d, a, b, c, x[i+ 8], 11, 0x8771F681); c = hh(c, d, a, b, x[i+11], 16, 0x6D9D6122); b = hh(b, c, d, a, x[i+14], 23, 0xFDE5380C); a = hh(a, b, c, d, x[i+ 1], 4 , 0xA4BEEA44); d = hh(d, a, b, c, x[i+ 4], 11, 0x4BDECFA9); c = hh(c, d, a, b, x[i+ 7], 16, 0xF6BB4B60); b = hh(b, c, d, a, x[i+10], 23, 0xBEBFBC70); a = hh(a, b, c, d, x[i+13], 4 , 0x289B7EC6); d = hh(d, a, b, c, x[i+ 0], 11, 0xEAA127FA); c = hh(c, d, a, b, x[i+ 3], 16, 0xD4EF3085); b = hh(b, c, d, a, x[i+ 6], 23, 0x04881D05); a = hh(a, b, c, d, x[i+ 9], 4 , 0xD9D4D039); d = hh(d, a, b, c, x[i+12], 11, 0xE6DB99E5); c = hh(c, d, a, b, x[i+15], 16, 0x1FA27CF8); b = hh(b, c, d, a, x[i+ 2], 23, 0xC4AC5665); a = ii(a, b, c, d, x[i+ 0], 6 , 0xF4292244); d = ii(d, a, b, c, x[i+ 7], 10, 0x432AFF97); c = ii(c, d, a, b, x[i+14], 15, 0xAB9423A7); b = ii(b, c, d, a, x[i+ 5], 21, 0xFC93A039); a = ii(a, b, c, d, x[i+12], 6 , 0x655B59C3); d = ii(d, a, b, c, x[i+ 3], 10, 0x8F0CCC92); c = ii(c, d, a, b, x[i+10], 15, 0xFFEFF47D); b = ii(b, c, d, a, x[i+ 1], 21, 0x85845DD1); a = ii(a, b, c, d, x[i+ 8], 6 , 0x6FA87E4F); d = ii(d, a, b, c, x[i+15], 10, 0xFE2CE6E0); c = ii(c, d, a, b, x[i+ 6], 15, 0xA3014314); b = ii(b, c, d, a, x[i+13], 21, 0x4E0811A1); a = ii(a, b, c, d, x[i+ 4], 6 , 0xF7537E82); d = ii(d, a, b, c, x[i+11], 10, 0xBD3AF235); c = ii(c, d, a, b, x[i+ 2], 15, 0x2AD7D2BB); b = ii(b, c, d, a, x[i+ 9], 21, 0xEB86D391); a = add(a, olda); b = add(b, oldb); c = add(c, oldc); d = add(d, oldd); } return rhex(a) + rhex(b) + rhex(c) + rhex(d); } } ii 回复于:2003-01-28 13:51:46 另: 一中国人写的md5 的javabean: /************************************************ MD5 算法的Java Bean @author:Topcat Tuppin Last Modified:10,Mar,2001 *************************************************/ //package beartool; import java.lang.reflect.*; /************************************************* md5 类实现了RSA Data Security, Inc.在提交给IETF 的RFC1321中的MD5 message-digest 算法。 *************************************************/ public class MD5 { /* 下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现中是用#define 实现的, 这里把它们实现成为static final是表示了只读,切能在同一个进程空间内的多个 Instance间共享*/ static final int S11 = 7; static final int S12 = 12; static final int S13 = 17; static final int S14 = 22; static final int S21 = 5; static final int S22 = 9; static final int S23 = 14; static final int S24 = 20; static final int S31 = 4; static final int S32 = 11; static final int S33 = 16; static final int S34 = 23; static final int S41 = 6; static final int S42 = 10; static final int S43 = 15; static final int S44 = 21; static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 下面的三个成员是MD5计算过程中用到的3个核心数据,在原始的C实现中 被定义到MD5_CTX结构中 */ private long[] state = new long[4]; // state (ABCD) private long[] count = new long[2]; // number of bits, modulo 2^64 (lsb first) private byte[] buffer = new byte[64]; // input buffer /* digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的 16进制ASCII表示. */ public String digestHexStr; /* digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值. */ private byte[] digest = new byte[16]; /* getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的. */ public String getMD5ofStr(String inbuf) { md5Init(); md5Update(inbuf.getBytes(), inbuf.length()); md5Final(); digestHexStr = ""; for (int i = 0; i < 16; i++) { digestHexStr += byteHEX(digest); } return digestHexStr; } // 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数 public MD5() { md5Init(); return; } /* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */ private void md5Init() { count[0] = 0L; count[1] = 0L; ///* Load magic initialization constants. state[0] = 0x67452301L; state[1] = 0xefcdab89L; state[2] = 0x98badcfeL; state[3] = 0x10325476L; return; } /* F, G, H ,I 是4个基本的MD5函数,在原始的MD5的C实现中,由于它们是 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java中,我们把它们 实现成了private方法,名字保持了原来C中的。 */ private long F(long x, long y, long z) { return (x &amp; y) | ((~x) &amp; z); } private long G(long x, long y, long z) { return (x &amp; z) | (y &amp; (~z)); } private long H(long x, long y, long z) { return x ^ y ^ z; } private long I(long x, long y, long z) { return y ^ (x | (~z)); } /* FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ private long FF(long a, long b, long c, long d, long x, long s, long ac) { a += F (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >;>;>; (32 - s)); a += b; return a; } private long GG(long a, long b, long c, long d, long x, long s, long ac) { a += G (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >;>;>; (32 - s)); a += b; return a; } private long HH(long a, long b, long c, long d, long x, long s, long ac) { a += H (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >;>;>; (32 - s)); a += b; return a; } private long II(long a, long b, long c, long d, long x, long s, long ac) { a += I (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >;>;>; (32 - s)); a += b; return a; } /* md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的 */ private void md5Update(byte[] inbuf, int inputLen) { int i, index, partLen; byte[] block = new byte[64]; index = (int)(count[0] >;>;>; 3) &amp; 0x3F; // /* Update number of bits */ if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++; count[1] += (inputLen >;>;>; 29); partLen = 64 - index; // Transform as many times as possible. if (inputLen >;= partLen) { md5Memcpy(buffer, inbuf, index, 0, partLen); md5Transform(buffer); for (i = partLen; i + 63 < inputLen; i += 64) { md5Memcpy(block, inbuf, 0, i, 64); md5Transform (block); } index = 0; } else i = 0; ///* Buffer remaining input */ md5Memcpy(buffer, inbuf, index, i, inputLen - i); } /* md5Final整理和填写输出结果 */ private void md5Final () { byte[] bits = new byte[8]; int index, padLen; ///* Save number of bits */ Encode (bits, count, 8); ///* Pad out to 56 mod 64. index = (int)(count[0] >;>;>; 3) &amp; 0x3f; padLen = (index < 56) ? (56 - index) : (120 - index); md5Update (PADDING, padLen); ///* Append length (before padding) */ md5Update(bits, 8); ///* Store state in digest */ Encode (digest, state, 16); } /* md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的 字节拷贝到output的outpos位置开始 */ private void md5Memcpy (byte[] output, byte[] input, int outpos, int inpos, int len) { int i; for (i = 0; i < len; i++) output[outpos + i] = input[inpos + i]; } /* md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节 */ private void md5Transform (byte block[]) { long a = state[0], b = state[1], c = state[2], d = state[3]; long[] x = new long[16]; Decode (x, block, 64); /* Round 1 */ a = FF (a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */ d = FF (d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */ c = FF (c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */ b = FF (b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */ a = FF (a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */ d = FF (d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */ c = FF (c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */ b = FF (b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */ a = FF (a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */ d = FF (d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */ c = FF (c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */ b = FF (b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */ a = FF (a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */ d = FF (d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */ c = FF (c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */ b = FF (b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */ /* Round 2 */ a = GG (a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */ d = GG (d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */ c = GG (c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */ b = GG (b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */ a = GG (a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */ d = GG (d, a, b, c, x[10], S22, 0x2441453L); /* 22 */ c = GG (c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */ b = GG (b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */ a = GG (a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */ d = GG (d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */ c = GG (c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */ b = GG (b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */ a = GG (a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */ d = GG (d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */ c = GG (c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */ b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */ /* Round 3 */ a = HH (a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */ d = HH (d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */ c = HH (c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */ b = HH (b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */ a = HH (a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */ d = HH (d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */ c = HH (c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */ b = HH (b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */ a = HH (a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */ d = HH (d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */ c = HH (c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */ b = HH (b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */ a = HH (a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */ d = HH (d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */ c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */ b = HH (b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */ /* Round 4 */ a = II (a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */ d = II (d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */ c = II (c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */ b = II (b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */ a = II (a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */ d = II (d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */ c = II (c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */ b = II (b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */ a = II (a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */ d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */ c = II (c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */ b = II (b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */ a = II (a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */ d = II (d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */ c = II (c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */ b = II (b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; } /*Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的, 只拆低32bit,以适应原始C实现的用途 */ private void Encode (byte[] output, long[] input, int len) { int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (byte)(input &amp; 0xffL); output[j + 1] = (byte)((input >;>;>; 8) &amp; 0xffL); output[j + 2] = (byte)((input >;>;>; 16) &amp; 0xffL); output[j + 3] = (byte)((input >;>;>; 24) &amp; 0xffL); } } /*Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的, 只合成低32bit,高32bit清零,以适应原始C实现的用途 */ private void Decode (long[] output, byte[] input, int len) { int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16) | (b2iu(input[j + 3]) << 24); return; } /* b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算 */ public static long b2iu(byte b) { return b < 0 ? b &amp; 0x7F + 128 : b; } /*byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示, 因为java中的byte的toString无法实现这一点,我们又没有C语言中的 sprintf(outbuf,"%02X",ib) */ public static String byteHEX(byte ib) { char[] Digit = { '0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; char [] ob = new char[2]; ob[0] = Digit[(ib >;>;>; 4) &amp; 0X0F]; ob[1] = Digit[ib &amp; 0X0F]; String s = new String(ob); return s; } public static void main(String args[]) { MD5 m = new MD5(); if (Array.getLength(args) == 0) { //如果没有参数,执行标准的Test Suite System.out.println("MD5 Test suite:"); System.out.println("MD5(\"\"):"+m.getMD5ofStr("")); System.out.println("MD5(\"a\"):"+m.getMD5ofStr("a")); System.out.println("MD5(\"abc\"):"+m.getMD5ofStr("abc")); System.out.println("MD5(\"message digest\"):"+m.getMD5ofStr("message digest")); System.out.println("MD5(\"abcdefghijklmnopqrstuvwxyz\"):"+ m.getMD5ofStr("abcdefghijklmnopqrstuvwxyz")); System.out.println("MD5(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"):"+ m.getMD5ofStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")); } else System.out.println("MD5(" + args[0] + ")=" + m.getMD5ofStr(args[0])); } } ii 回复于:2003-02-09 09:40:22 再次改人家的程序,来简化处理. // 程序名为MMM.java package md5; import java.security.*; public class MMM { public String calcMD5(String str) { try { MessageDigest alga=MessageDigest.getInstance("MD5"); // MessageDigest alga=MessageDigest.getInstance("SHA-1"); alga.update(str.getBytes()); byte[] digesta=alga.digest(); return byte2hex(digesta); } catch (NoSuchAlgorithmException ex) { System.out.println("大哥,出错了!!"); } return "NULL"; } public String byte2hex(byte[] b) { //二行制转字符串 String hs=""; String stmp=""; for (int n=0;n<b.length;n++) { stmp=(Integer.toHexString(b[n] &amp; 0XFF)); if (stmp.length()==1) hs=hs+"0"+stmp; else hs=hs+stmp; if (n<b.length-1) hs=hs+""; } // return hs.toUpperCase(); return hs; } } 本文转自博客园执着的笨蛋的博客,原文链接:[精华] md5算法的java源代码,如需转载请自行联系原博主。
存储过程里的事务操作:create or replace procedure pr_mypro2(p_a in varchar2,p_b in varchar2,p_count out number)temp varchar2(1000); /**//*定义临时变量*/isbeginselect code into p_count from table1 where a=p_a; /**//*查询并返回值*/temp := p_count; /**//*将返回值赋给临时变量*/savepoint point1; /**//*保存点*/insert into table2(a,b)values(temp,p_b); /**//*将临时变量值添加到新表的字段*/savepoint point2;insert into exception when others then rollback to savepoint point1; /**//*异常处理,保存点下面的操作都不会被执行*/ return;end; 保存点(SAVEPOINT)是事务处理过程中的一个标志,与回滚命令(ROLLBACK)结合使用,主要的用途是允许用户将某一段处理回滚而不必回滚整个事务。 如果定义了多个savepoint,当指定回滚到某个savepoint时,那么回滚操作将回滚这个savepoint后面的所有操作(即使后面可能标记了N个savepoint)。例如,在一段处理中定义了五个savepoint,从第三个savepoint回滚,后面的第四、第五个标记的操作都将被回滚,如果不使用ROLLBACK TO savepoint_name而使用ROLLBACK,将会滚整个事务处理。 本文转自博客园沉睡森林@漂在北京的博客,原文链接:存储过程事务控制,如需转载请自行联系原博主。
写出来的文件用浏览器打开后都是乱码。已经在XML的最前面加上了 <?xml version="1.0" encoding="UTF-8"?> 而且浏览器的编码也是UTF-8的,这就排除了浏览器的问题。 再用VIM打开,发现用GB2312看是没问题的,换成:set encoding=UTF-8以后开始乱码 这时我尝试将字符串转码后写入文件,但在UTF-8,GBK和ISO8859_1中间怎么转也没有用。 忽然想起前几天yiyayoyo同学和我提过Java写文件默认编码的问题,于是开始google,发现我用的写文件的方式无法指定编码,于是换用另一种写文件的方式指定UTF-8,遂搞定。代码如下: 老代码: PrintWriter pw = new PrintWriter(new FileWriter(path)); pw.print(content); pw.close(); 新代码: FileOutputStream fos = new FileOutputStream(path); Writer out = new OutputStreamWriter(fos, "UTF-8"); out.write(content); out.close(); fos.close(); 顺便抱怨一句,Java中写文件的方式还真是多阿多……我等一两年经验的小程序员看了都眼晕 库卡 说: 读代码也有编码的问题,如果要读取UTF-8的文件,应采用如下方式覆盖默认编码: FileInputStream fis = new FileInputStream(s); StringBuffer content = new StringBuffer(); DataInputStream in = new DataInputStream(fis); BufferedReader d = new BufferedReader(new InputStreamReader(in, "UTF-8")); String line = null; while ((line = d.readLine()) != null) content.append(line + "\n"); d.close(); in.close(); fis.close(); 本文转自博客园执着的笨蛋的博客,原文链接:在Java中写文件的中文问题[转],如需转载请自行联系原博主。
1、选取最适用的字段属性 MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGIN来定义整型字段。 另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库不用去比较NULL值。 对于某些文本字段,例如“省份”或者“性别”,我们可以将它们定义为ENUM类型。因为在MySQL中,ENUM类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。 2、使用连接(JOIN)来代替子查询(Sub-Queries) MySQL从4.1开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询,如下所示: DELETE FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo ) 使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN).. 替代。例如,假设我们要将所有没有订单记录的用户取出来,可以用下面这个查询完成: SELECT * FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo ) 如果使用连接(JOIN).. 来完成这个查询工作,速度将会快很多。尤其是当salesinfo表中对CustomerID建有索引的话,性能将会更好,查询如下: SELECT * FROM customerinfo LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo. CustomerID WHERE salesinfo.CustomerID IS NULL 连接(JOIN).. 之所以更有效率一些,是因为 MySQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。 3、使用联合(UNION)来代替手动创建的临时表 MySQL 从 4.0 的版本开始支持 UNION 查询,它可以把需要使用临时表的两条或更多的 SELECT 查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用 UNION 来创建查询的时候,我们只需要用 UNION作为关键字把多个 SELECT 语句连接起来就可以了,要注意的是所有 SELECT 语句中的字段数目要想同。下面的例子就演示了一个使用 UNION的查询。 SELECT Name, Phone FROM client UNION SELECT Name, BirthDate FROM author UNION SELECT Name, Supplier FROM product 4、事务 尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以BEGIN 关键字开始,COMMIT关键字结束。在这之间的一条SQL操作失败,那么,ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。 BEGIN; INSERT INTO salesinfo SET CustomerID=14; UPDATE inventory SET Quantity=11 WHERE item='book'; COMMIT; 事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。 5、锁定表 尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户 来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,例如访问一个电子商务网站,就会产生比较严重的响应延迟。 其实,有些情况下我们可以通过锁定表的方法来获得更好的性能。下面的例子就用锁定表的方法来完成前面一个例子中事务的功能。 LOCK TABLE inventory WRITE SELECT Quantity FROM inventory WHEREItem='book'; ... UPDATE inventory SET Quantity=11 WHEREItem='book'; UNLOCK TABLES 这里,我们用一个 SELECT 语句取出初始数据,通过一些计算,用 UPDATE 语句将新值更新到表中。包含有 WRITE 关键字的 LOCK TABLE 语句可以保证在 UNLOCK TABLES 命令被执行之前,不会有其它的访问来对 inventory 进行插入、更新或者删除的操作。 6、使用外键 锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。例如,外键可以保证每一条销售记录都指向某一个存在的客户。在这里,外键可以把customerinfo 表中的CustomerID映射到salesinfo表中CustomerID,任何一条没有合法CustomerID的记录都不会被更新或插入到salesinfo中。 CREATE TABLE customerinfo ( CustomerID INT NOT NULL , PRIMARY KEY ( CustomerID ) ) TYPE = INNODB; CREATE TABLE salesinfo ( SalesID INT NOT NULL, CustomerID INT NOT NULL, PRIMARY KEY(CustomerID, SalesID), FOREIGN KEY (CustomerID) REFERENCES customerinfo (CustomerID) ON DELETECASCADE ) TYPE = INNODB; 注意例子中的参数“ON DELETE CASCADE”。该参数保证当 customerinfo 表中的一条客户记录被删除的时候,salesinfo 表中所有与该客户相关的记录也会被自动删除。如果要在 MySQL 中使用外键,一定要记住在创建表的时候将表的类型定义为事务安全表 InnoDB类型。该类型不是 MySQL 表的默认类型。定义的方法是在 CREATE TABLE 语句中加上 TYPE=INNODB。如例中所示。 7、使用索引 索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(), MIN()和ORDERBY这些命令的时候,性能提高更为明显。那该对哪些字段建立索引呢?一般说来,索引应建立在那些将用于JOIN, WHERE判断和ORDER BY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个ENUM类型的字段来说,出现大量重复值是很有可能的情况,例如customerinfo中的“province”.. 字段,在这样的字段上建立索引将不会有什么帮助;相反,还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引,也可以使用ALTER TABLE或CREATE INDEX在以后创建索引。此外,MySQL 从版本3.23.23开始支持全文索引和搜索。全文索引在MySQL 中是一个FULLTEXT类型索引,但仅能用于MyISAM 类型的表。对于一个大的数据库,将数据装载到一个没有FULLTEXT索引的表中,然后再使用ALTER TABLE或CREATE INDEX创建索引,将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中,执行过程将会非常慢。 8、优化的查询语句 绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。下面是应该注意的几个方面。首先,最好是在相同类型的字段间进行比较的操作。在MySQL 3.23版之前,这甚至是一个必须的条件。例如不能将一个建有索引的INT字段和BIGINT字段进行比较;但是作为特殊的情况,在CHAR类型的字段和VARCHAR类型字段的字段大小相同的时候,可以将它们进行比较。其次,在建有索引的字段上尽量不要使用函数进行操作。 例如,在一个DATE类型的字段上使用YEAE()函数时,将会使索引不能发挥应有的作用。所以,下面的两个查询虽然返回的结果一样,但后者要比前者快得多。 SELECT * FROM order WHERE YEAR(OrderDate)<2001; SELECT * FROM order WHERE OrderDate<"2001-01-01"; 同样的情形也会发生在对数值型字段进行计算的时候: SELECT * FROM inventory WHERE Amount/7<24; SELECT * FROM inventory WHERE Amount<24*7; 上面的两个查询也是返回相同的结果,但后面的查询将比前面的一个快很多。第三,在搜索字符型字段时,我们有时会使用 LIKE 关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。例如下面的查询将会比较表中的每一条记录。 SELECT * FROM books WHERE name like "MySQL%" 但是如果换用下面的查询,返回的结果一样,但速度就要快上很多: SELECT * FROM books WHERE name>="MySQL"and name<"mysqm" 最后,应该注意避免在查询中让MySQL进行自动类型转换,因为转换过程也会使索引变得不起作用。 本文转自博客园执着的笨蛋的博客,原文链接:完全优化MySQL数据库性能的八大巧方法,如需转载请自行联系原博主。
很早以前,也是一提到SQL Server,就觉得它的性能没法跟Oracle相比,一提到大数据处理就想到Oracle。自己一路走来,在本地blog上记录了很多优化方面的 post,对的错的都有,没有时间系列的整理出来,这篇文章将join方法的概念稍微整理在一起,给大家个参考。通过查资料了解里面提到的各种概念,在实 际中不断验证总结,完全可以对数据库一步步深入理解下去的。 我只对SQL Server 2000比较了解,但这并不阻碍我在Oracle、MySql进行SQL调优、产品架构,因为在数据库理论原理上,各大数据库基本出入不大,对数据库的深入理解,也不会影响你架构设计思想变坏,相反给你带来的是更深层次的思考。 关于执行计划的说明 在SQL Server查询分析器的Query菜单中选择Show Execution Plan,运行SQL查询语句,在结果窗口中有Grid、Execution Plan、Messages三个Tab。看图形形式的执行计划,顺序是从右到左,这也是执行的顺序。执行计划中的每一个图标表示一个操作,每一个操作都会 有一个或多个输入,也会有一个或多个输出。输入和输出,有可能是一个物理数据表、索引数据结构,或者是执行过程中的一些中间结果集/数据结构。鼠标移动到 图标上,会显示这个操作的具体信息,例如逻辑和物理操作名称、记录的数量和大小、I/O成本、CPU成本、操作的具体表达式(参数Argument)。鼠 标移动到连接箭头上,会显示箭头起始端的操作输出结果集的记录数、记录的大小,一般情况下可以将这个输出结果集理解为箭头结束端的输入。 另 外关于执行计划的一些补充说明:1. 执行计划中显示的信息,都是一个“评估”的结果,不是100%准确的信息,例如记录数量是取自统计信息,I/O成本、CPU成本来自执行计划生成过程中基 于统计信息等得出的评估结果。2. 执行计划不一定准确,一方面受SQL Server维护的统计信息准确性的影响,另一方面SQL语句编译时刻与执行时刻的环境(内存使用状况、CPU状况等)可能会不一样。 关于统计信息、I/O成本和CPU成本的评估、SQL语句的编译和执行过程,这里不再深入。另外尽管执行计划不一定准确,但它仍是SQL语句分析最重要的依据,因为你可以理解为,绝大部分情况下,SQL Server是以这种方式来执行的。 JOIN方法说明 数据库中,象tableA inner join tableB、tableA left out join tableB这样的SQL语句是如何执行join操作的?就是说SQL Server使用什么算法实现两个表数据的join操作? SQL Server 2000有三种方式:nested loop、merge、hash。Oracle也是使用这三种方式,不过Oracle选择使用nested loop的条件跟SQL Server有点差别,内存管理机制跟SQL Server不一样,因此查看执行计划,Oracle中nested loop运用非常多,而merge和hash方式相对较少,SQL Server中,merge跟hash方式则是非常普遍。 以SQL Server 2000为例对这三种方式进行说明,穿插在里面讲解执行计划的一些初级使用。 1. nested loop join 1.1 示例SQL select ... from tableA inner join tableB on tableA.col1=tableB.col1 where tableA.col2=? and tableB.col2=?tableA中没有建立任何索引,tableB中在col1上有建立一个主键(聚集索引)。 1.2 算法伪代码描述 foreach rowA in tableA where tableA.col2=?{search rowsB from tableB where tableB.col1=rowA.col1 and tableB.col2=? ;if(rowsB.Count<=0)discard rowA ;elseoutput rowA and rowsB ;} join操作有两个输入,上面例子中tableA是outer input,用于外层循环;tableB是inner input,用于循环内部。下面针对执行计划描述一下SQL Server完成这个操作的具体步骤。 %. ^ g.L 2vt [ AhVA 1.3 查看执行计划方法 移到文章最前面。 1.4 执行步骤 下 面是示例SQL的执行计划图。 nested loop操作的右边,位于上面的是outer input,位于下面的是inner input。你不能够根据join中哪个表出现在前面来确定outer input和inner input关系,而必须从执行计划中来确定,因为SQL Server会自动选择哪个作为inner input。 本文转自博客园执着的笨蛋的博客,原文链接:SQL数据库使用JOIN的优化方法,如需转载请自行联系原博主。
1. 原始单据与实体之间的关系 可以是一对一、一对多、多对多的关系。在一般情况下,它们是一对一的关系:即一张原始单据对 应且只对应一个实体。在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实 体,或多张原始单证对应一个实体。这里的实体可以理解为基本表。明确这种对应关系后,对我们设计 录入界面大有好处。 〖例1〗:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表、社会 关系表、工作简历表。这就是“一张原始单证对应多个实体”的典型例子。 2. 主键与外键 一般而言,一个实体不能既无主键又无外键。在E—R 图中, 处于叶子部位的实体, 可以定义主键, 也可以不定义主键(因为它无子孙), 但必须要有外键(因为它有父亲)。 主键与外键的设计,在全局数据库的设计中,占有重要地位。当全局数据库的设计完成以后,有个 美国数据库设计专家说:“键,到处都是键,除了键之外,什么也没有”,这就是他的数据库设计经验 之谈,也反映了他对信息系统核心(数据模型)的高度抽象思想。因为:主键是实体的高度抽象,主键与 外键的配对,表示实体之间的连接。 3. 基本表的性质 基本表与中间表、临时表不同,因为它具有如下四个特性: (1) 原子性。基本表中的字段是不可再分解的。 (2) 原始性。基本表中的记录是原始数据(基础数据)的记录。 (3) 演绎性。由基本表与代码表中的数据,可以派生出所有的输出数据。 (4) 稳定性。基本表的结构是相对稳定的,表中的记录是要长期保存的。 理解基本表的性质后,在设计数据库时,就能将基本表与中间表、临时表区分开来。 4. 范式标准 基本表及其字段之间的关系, 应尽量满足第三范式。但是,满足第三范式的数据库设计,往往不是 最好的设计。为了提高数据库的运行效率,常常需要降低范式标准:适当增加冗余,达到以空间换时间 的目的。 〖例2〗:有一张存放商品的基本表,如表1所示。“金额”这个字段的存在,表明该表的设计不满 足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加 “金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。 在Rose 2002中,规定列有两种类型:数据列和计算列。“金额”这样的列被称为“计算列”,而“ 单价”和“数量”这样的列被称为“数据列”。 表1 商品表的表结构 商品名称 商品型号 单价 数量 金额 电视机 29吋 2,500 40 100,000 5. 通俗地理解三个范式 通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就 必须通俗地理解三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解): 第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解; 第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性; 第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余 。 没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运 行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式 ,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。 6. 要善于识别与正确处理多对多的关系 若两个实体之间存在多对多的关系,则应消除这种关系。消除的办法是,在两者之间增加第三个实 体。这样,原来一个多对多的关系,现在变为两个一对多的关系。要将原来两个实体的属性合理地分配 到三个实体中去。这里的第三个实体,实质上是一个较复杂的关系,它对应一张基本表。一般来讲,数 据库设计工具不能识别多对多的关系,但能处理多对多的关系。 〖例3〗:在“图书馆信息系统”中,“图书”是一个实体,“读者”也是一个实体。这两个实体之 间的关系,是一个典型的多对多关系:一本图书在不同时间可以被多个读者借阅,一个读者又可以借多 本图书。为此,要在二者之间增加第三个实体,该实体取名为“借还书”,它的属性为:借还时间、借 还标志(0表示借书,1表示还书),另外,它还应该有两个外键(“图书”的主键,“读者”的主键),使 它能与“图书”和“读者”连接。 7. 主键PK的取值方法 PK是供程序员使用的表间连接工具,可以是一无物理意义的数字串, 由程序自动加1来实现。也可 以是有物理意义的字段名或字段名的组合。不过前者比后者好。当PK是字段名的组合时,建议字段的个 数不要太多,多了不但索引占用空间大,而且速度也慢。 8. 正确认识数据冗余 主键与外键在多表中的重复出现, 不属于数据冗余,这个概念必须清楚,事实上有许多人还不清楚 。非键字段的重复出现, 才是数据冗余!而且是一种低级冗余,即重复性的冗余。高级冗余不是字段的 重复出现,而是字段的派生出现。 〖例4〗:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出 来的,它就是冗余,而且是一种高级冗余。冗余的目的是为了提高处理速度。只有低级冗余才会增加数 据的不一致性,因为同一数据,可能从不同时间、地点、角色上多次录入。因此,我们提倡高级冗余(派 生性冗余),反对低级冗余(重复性冗余)。 9. E--R图没有标准答案 信息系统的E--R图没有标准答案,因为它的设计与画法不是惟一的,只要它覆盖了系统需求的业务 范围和功能内容,就是可行的。反之要修改E--R图。尽管它没有惟一的标准答案,并不意味着可以随意 设计。好的E—R图的标准是:结构清晰、关联简洁、实体个数适中、属性分配合理、没有低级冗余。 10. 视图技术在数据库设计中很有用 与基本表、代码表、中间表不同,视图是一种虚表,它依赖数据源的实表而存在。视图是供程序员 使用数据库的一个窗口,是基表数据综合的一种形式, 是数据处理的一种方法,是用户数据保密的一种 手段。为了进行复杂处理、提高运算速度和节省存储空间, 视图的定义深度一般不得超过三层。 若三层 视图仍不够用, 则应在视图上定义临时表, 在临时表上再定义视图。这样反复交迭定义, 视图的深度就 不受限制了。 对于某些与国家政治、经济、技术、军事和安全利益有关的信息系统,视图的作用更加重要。这些 系统的基本表完成物理设计之后,立即在基本表上建立第一层视图,这层视图的个数和结构,与基本表 的个数和结构是完全相同。并且规定,所有的程序员,一律只准在视图上操作。只有数据库管理员,带 着多个人员共同掌握的“安全钥匙”,才能直接在基本表上操作。请读者想想:这是为什么? 11. 中间表、报表和临时表 中间表是存放统计数据的表,它是为数据仓库、输出报表或查询结果而设计的,有时它没有主键与 外键(数据仓库除外)。临时表是程序员个人设计的,存放临时记录,为个人所用。基表和中间表由DBA维 护,临时表由程序员自己用程序自动维护。 12. 完整性约束表现在三个方面 域的完整性:用Check来实现约束,在数据库设计工具中,对字段的取值范围进行定义时,有一个Ch eck按钮,通过它定义字段的值城。 参照完整性:用PK、FK、表级触发器来实现。 用户定义完整性:它是一些业务规则,用存储过程和触发器来实现。 13. 防止数据库设计打补丁的方法是“三少原则” (1) 一个数据库中表的个数越少越好。只有表的个数少了,才能说明系统的E--R图少而精,去掉了 重复的多余的实体,形成了对客观世界的高度抽象,进行了系统的数据集成,防止了打补丁式的设计; (2) 一个表中组合主键的字段个数越少越好。因为主键的作用,一是建主键索引,二是做为子表的 外键,所以组合主键的字段个数少了,不仅节省了运行时间,而且节省了索引存储空间; (3) 一个表中的字段个数越少越好。只有字段的个数少了,才能说明在系统中不存在数据重复,且 很少有数据冗余,更重要的是督促读者学会“列变行”,这样就防止了将子表中的字段拉入到主表中去 ,在主表中留下许多空余的字段。所谓“列变行”,就是将主表中的一部分内容拉出去,另外单独建一 个子表。这个方法很简单,有的人就是不习惯、不采纳、不执行。 数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点。“三少”是一个整体概 念,综合观点,不能孤立某一个原则。该原则是相对的,不是绝对的。“三多”原则肯定是错误的。试 想:若覆盖系统同样的功能,一百个实体(共一千个属性) 的E--R图,肯定比二百个实体(共二千个属性) 的E--R图,要好得多。 提倡“三少”原则,是叫读者学会利用数据库设计技术进行系统的数据集成。数据集成的步骤是将 文件系统集成为应用数据库,将应用数据库集成为主题数据库,将主题数据库集成为全局综合数据库。 集成的程度越高,数据共享性就越强,信息孤岛现象就越少,整个企业信息系统的全局E—R图中实体的 个数、主键的个数、属性的个数就会越少。 提倡“三少”原则的目的,是防止读者利用打补丁技术,不断地对数据库进行增删改,使企业数据 库变成了随意设计数据库表的“垃圾堆”,或数据库表的“大杂院”,最后造成数据库中的基本表、代 码表、中间表、临时表杂乱无章,不计其数,导致企事业单位的信息系统无法维护而瘫痪。 “三多”原则任何人都可以做到,该原则是“打补丁方法”设计数据库的歪理学说。“三少”原则 是少而精的原则,它要求有较高的数据库设计技巧与艺术,不是任何人都能做到的,因为该原则是杜绝 用“打补丁方法”设计数据库的理论依据。 14. 提高数据库运行效率的办法 在给定的系统硬件和系统软件条件下,提高数据库系统的运行效率的办法是: (1) 在数据库物理设计时,降低范式,增加冗余, 少用触发器, 多用存储过程。 (2) 当计算非常复杂、而且记录条数非常巨大时(例如一千万条),复杂计算要先在数据库外面,以 文件系统方式用C++语言计算处理完成之后,最后才入库追加到表中去。这是电信计费系统设计的经验。 (3) 发现某个表的记录太多,例如超过一千万条,则要对该表进行水平分割。水平分割的做法是, 以该表主键PK的某个值为界线,将该表的记录水平分割为两个表。若发现某个表的字段太多,例如超过 八十个,则垂直分割该表,将原来的一个表分解为两个表。 (4) 对数据库管理系统DBMS进行系统优化,即优化各种系统参数,如缓冲区个数。 (5) 在使用面向数据的SQL语言进行程序设计时,尽量采取优化算法。 总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化 ,这三个层次上同时下功夫。 上述十四个技巧,是许多人在大量的数据库分析与设计实践中,逐步总结出来的。对于这些经验的 运用,读者不能生帮硬套,死记硬背,而要消化理解,实事求是,灵活掌握。并逐步做到:在应用中发 展,在发展中应用。 本文转自博客园执着的笨蛋的博客,原文链接:数据库设计中的14个技巧,如需转载请自行联系原博主。
本文首先讨论了基于第三范式的数据库表的基本设计,着重论述了建立主键和索引的策略和方案,然后从数据库表的扩展设计和库表对象的放置等角度概述了数据库管理系统的优化方案。 1 引言 数据库优化的目标无非是避免磁盘I/O瓶颈、减少CPU利用率和减少资源竞争。为了便于读者阅读和理解,笔者参阅了Sybase、Informix和Oracle等大型数据库系统参考资料,基于多年的工程实践经验,从基本表设计、扩展设计和数据库表对象放置等角度进行讨论,着重讨论了如何避免磁盘I/O瓶颈和减少资源竞争,相信读者会一目了然。 2 基于第三范式的基本表设计 在基于表驱动的信息管理系统(MIS)中,基本表的设计规范是第三范式(3NF)。第三范式的基本特征是非主键属性只依赖于主键属性。基于第三范式的数据库表设计具有很多优点:一是消除了冗余数据,节省了磁盘存储空间;二是有良好的数据完整性限制,即基于主外键的参照完整限制和基于主键的实体完整性限制,这使得数据容易维护,也容易移植和更新;三是数据的可逆性好,在做连接(Join)查询或者合并表时不遗漏、也不重复;四是因消除了冗余数据(冗余列), 在查询(Select)时每个数据页存的数据行就多,这样就有效地减少了逻辑I/O,每个Cash存的页面就多,也减少物理I/O;五是对大多数事务(Transaction)而言,运行性能好;六是物理设计(Physical Design)的机动性较大,能满足日益增长的用户需求。 在基本表设计中,表的主键、外键、索引设计占有非常重要的地位,但系统设计人员往往只注重于满足用户要求,而没有从系统优化的高度来认识和重视它们。实际上,它们与系统的运行性能密切相关。现在从系统数据库优化角度讨论这些基本概念及其重要意义: (1)主键(Primary Key):主键被用于复杂的SQL语句时,频繁地在数据访问中被用到。一个表只有一个主键。主键应该有固定值(不能为Null或缺省值,要有相对稳定性),不含代码信息,易访问。把常用(众所周知)的列作为主键才有意义。短主键最佳(小于25bytes),主键的长短影响索引的大小,索引的大小影响索引页的大小,从而影响磁盘I/O。主键分为自然主键和人为主键。自然主键由实体的属性构成,自然主键可以是复合性的,在形成复合主键时,主键列不能太多,复合主键使得Join*作复杂化、也增加了外键表的大小。人为主键是,在没有合适的自然属性键、或自然属性复杂或灵敏度高时,人为形成的。人为主键一般是整型值(满足最小化要求),没有实际意义,也略微增加了表的大小;但减少了把它作为外键的表的大小。 (2)外键(Foreign Key):外键的作用是建立关系型数据库中表之间的关系(参照完整性),主键只能从独立的实体迁移到非独立的实体,成为后者的一个属性,被称为外键。 (3)索引(Index):利用索引优化系统性能是显而易见的,对所有常用于查询中的Where子句的列和所有用于排序的列创建索引,可以避免整表扫描或访问,在不改变表的物理结构的情况下,直接访问特定的数据列,这样减少数据存取时间;利用索引可以优化或排除耗时的分类*作;把数据分散到不同的页面上,就分散了插入的数据;主键自动建立了唯一索引,因此唯一索引也能确保数据的唯一性(即实体完整性);索引码越小,定位就越直接;新建的索引效能最好,因此定期更新索引非常必要。索引也有代价:有空间开销,建立它也要花费时间,在进行Insert、Delete和Update*作时,也有维护代价。索引有两种:聚族索引和非聚族索引。一个表只能有一个聚族索引,可有多个非聚族索引。使用聚族索引查询数据要比使用非聚族索引快。在建索引前,应利用数据库系统函数估算索引的大小。 ① 聚族索引(Clustered Index):聚族索引的数据页按物理有序储存,占用空间小。选择策略是,被用于Where子句的列:包括范围查询、模糊查询或高度重复的列(连续磁盘扫描);被用于连接Join*作的列;被用于Order by和Group by子句的列。聚族索引不利于插入*作,另外没有必要用主键建聚族索引。 ② 非聚族索引(Nonclustered Index):与聚族索引相比,占用空间大,而且效率低。选择策略是,被用于Where子句的列:包括范围查询、模糊查询(在没有聚族索引时)、主键或外键列、点(指针类)或小范围(返回的结果域小于整表数据的20%)查询;被用于连接Join*作的列、主键列(范围查询);被用于Order by和Group by子句的列;需要被覆盖的列。对只读表建多个非聚族索引有利。索引也有其弊端,一是创建索引要耗费时间,二是索引要占有大量磁盘空间,三是增加了维护代价(在修改带索引的数据列时索引会减缓修改速度)。那么,在哪种情况下不建索引呢?对于小表(数据小于5页)、小到中表(不直接访问单行数据或结果集不用排序)、单值域(返回值密集)、索引列值太长(大于20bitys)、容易变化的列、高度重复的列、Null值列,对没有被用于Where子语句和Join查询的列都不能建索引。另外,对主要用于数据录入的,尽可能少建索引。当然,也要防止建立无效索引,当Where语句中多于5个条件时,维护索引的开销大于索引的效益,这时,建立临时表存储有关数据更有效。 批量导入数据时的注意事项:在实际应用中,大批量的计算(如电信话单计费)用C语言程序做,这种基于主外键关系数据计算而得的批量数据(文本文件),可利用系统的自身功能函数(如Sybase的BCP命令)快速批量导入,在导入数据库表时,可先删除相应库表的索引,这有利于加快导入速度,减少导入时间。在导入后再重建索引以便优化查询。 (4)锁:锁是并行处理的重要机制,能保持数据并发的一致性,即按事务进行处理;系统利用锁,保证数据完整性。因此,我们避免不了死锁,但在设计时可以充分考虑如何避免长事务,减少排它锁时间,减少在事务中与用户的交互,杜绝让用户控制事务的长短;要避免批量数据同时执行,尤其是耗时并用到相同的数据表。锁的征用:一个表同时只能有一个排它锁,一个用户用时,其它用户在等待。若用户数增加,则Server的性能下降,出现“假死”现象。如何避免死锁呢?从页级锁到行级锁,减少了锁征用;给小表增加无效记录,从页级锁到行级锁没有影响,若在同一页内竞争有影响,可选择合适的聚族索引把数据分配到不同的页面;创建冗余表;保持事务简短;同一批处理应该没有网络交互。 (5)查询优化规则:在访问数据库表的数据(Access Data)时,要尽可能避免排序(Sort)、连接(Join)和相关子查询*作。经验告诉我们,在优化查询时,必须做到: ① 尽可能少的行; ② 避免排序或为尽可能少的行排序,若要做大量数据排序,最好将相关数据放在临时表中*作;用简单的键(列)排序,如整型或短字符串排序; ③ 避免表内的相关子查询; ④ 避免在Where子句中使用复杂的表达式或非起始的子字符串、用长字符串连接; ⑤ 在Where子句中多使用“与”(And)连接,少使用“或”(Or)连接; ⑥ 利用临时数据库。在查询多表、有多个连接、查询复杂、数据要过滤时,可以建临时表(索引)以减少I/O。但缺点是增加了空间开销。 除非每个列都有索引支持,否则在有连接的查询时分别找出两个动态索引,放在工作表中重新排序。 3 基本表扩展设计 基于第三范式设计的库表虽然有其优越性(见本文第一部分),然而在实际应用中有时不利于系统运行性能的优化:如需要部分数据时而要扫描整表,许多过程同时竞争同一数据,反复用相同行计算相同的结果,过程从多表获取数据时引发大量的连接*作,当数据来源于多表时的连接*作;这都消耗了磁盘I/O和CPU时间。 尤其在遇到下列情形时,我们要对基本表进行扩展设计:许多过程要频繁访问一个表、子集数据访问、重复计算和冗余数据,有时用户要求一些过程优先或低的响应时间。 如何避免这些不利因素呢?根据访问的频繁程度对相关表进行分割处理、存储冗余数据、存储衍生列、合并相关表处理,这些都是克服这些不利因素和优化系统运行的有效途径。 3.1 分割表或储存冗余数据 分割表分为水平分割表和垂直分割表两种。分割表增加了维护数据完整性的代价。 水平分割表:一种是当多个过程频繁访问数据表的不同行时,水平分割表,并消除新表中的冗余数据列;若个别过程要访问整个数据,则要用连接*作,这也无妨分割表;典型案例是电信话单按月分割存放。另一种是当主要过程要重复访问部分行时,最好将被重复访问的这些行单独形成子集表(冗余储存),这在不考虑磁盘空间开销时显得十分重要;但在分割表以后,增加了维护难度,要用触发器立即更新、或存储过程或应用代码批量更新,这也会增加额外的磁盘I/O开销。 垂直分割表(不破坏第三范式),一种是当多个过程频繁访问表的不同列时,可将表垂直分成几个表,减少磁盘I/O(每行的数据列少,每页存的数据行就多,相应占用的页就少),更新时不必考虑锁,没有冗余数据。缺点是要在插入或删除数据时要考虑数据的完整性,用存储过程维护。另一种是当主要过程反复访问部分列时,最好将这部分被频繁访问的列数据单独存为一个子集表(冗余储存),这在不考虑磁盘空间开销时显得十分重要;但这增加了重叠列的维护难度,要用触发器立即更新、或存储过程或应用代码批量更新,这也会增加额外的磁盘I/O开销。垂直分割表可以达到最大化利用Cache的目的。 总之,为主要过程分割表的方法适用于:各个过程需要表的不联结的子集,各个过程需要表的子集,访问频率高的主要过程不需要整表。在主要的、频繁访问的主表需要表的子集而其它主要频繁访问的过程需要整表时则产生冗余子集表。 注意,在分割表以后,要考虑重新建立索引。 3.2 存储衍生数据 对一些要做大量重复性计算的过程而言,若重复计算过程得到的结果相同(源列数据稳定,因此计算结果也不变),或计算牵扯多行数据需额外的磁盘I/O开销,或计算复杂需要大量的CPU时间,就考虑存储计算结果(冗余储存)。现予以分类说明: 若在一行内重复计算,就在表内增加列存储结果。但若参与计算的列被更新时,必须要用触发器更新这个新列。 若对表按类进行重复计算,就增加新表(一般而言,存放类和结果两列就可以了)存储相关结果。但若参与计算的列被更新时,就必须要用触发器立即更新、或存储过程或应用代码批量更新这个新表。 若对多行进行重复性计算(如排名次),就在表内增加列存储结果。但若参与计算的列被更新时,必须要用触发器或存储过程更新这个新列。 总之,存储冗余数据有利于加快访问速度;但违反了第三范式,这会增加维护数据完整性的代价,必须用触发器立即更新、或存储过程或应用代码批量更新,以维护数据的完整性。 3.3 消除昂贵结合 对于频繁同时访问多表的一些主要过程,考虑在主表内存储冗余数据,即存储冗余列或衍生列(它不依赖于主键),但破坏了第三范式,也增加了维护难度。在源表的相关列发生变化时,必须要用触发器或存储过程更新这个冗余列。当主要过程总同时访问两个表时可以合并表,这样可以减少磁盘I/O*作,但破坏了第三范式,也增加了维护难度。对父子表和1:1关系表合并方法不同:合并父子表后,产生冗余表;合并1:1关系表后,在表内产生冗余数据。 4 数据库对象的放置策略 数据库对象的放置策略是均匀地把数据分布在系统的磁盘中,平衡I/O访问,避免I/O瓶颈。 ⑴ 访问分散到不同的磁盘,即使用户数据尽可能跨越多个设备,多个I/O运转,避免I/O竞争,克服访问瓶颈;分别放置随机访问和连续访问数据。 ⑵ 分离系统数据库I/O和应用数据库I/O。把系统审计表和临时库表放在不忙的磁盘上。 ⑶ 把事务日志放在单独的磁盘上,减少磁盘I/O开销,这还有利于在障碍后恢复,提高了系统的安全性。 ⑷ 把频繁访问的“活性”表放在不同的磁盘上;把频繁用的表、频繁做Join*作的表分别放在单独的磁盘上,甚至把把频繁访问的表的字段放在不同的磁盘上,把访问分散到不同的磁盘上,避免I/O争夺; ⑸ 利用段分离频繁访问的表及其索引(非聚族的)、分离文本和图像数据。段的目的是平衡I/O,避免瓶颈,增加吞吐量,实现并行扫描,提高并发度,最大化磁盘的吞吐量。利用逻辑段功能,分别放置“活性”表及其非聚族索引以平衡I/O。当然最好利用系统的默认段。另外,利用段可以使备份和恢复数据更加灵活,使系统授权更加灵活。 本文转自博客园执着的笨蛋的博客,原文链接:数据库优化设计方案,如需转载请自行联系原博主。
以下是针对事务型数据库: 1.是否使用联合主键?个人倾向于少采用联合主键。因为这样会降低索引的效率,联合主键一般都要用到至少一个业务字段,往往是字符串型的,而且理论上多字段的索引比单字段的索引要慢些。看上去似乎也不那么清爽。 在实际的设计中,我尽量避免使用联合主键,有些时候“不得不”使用联合主键。 2.PK采用无意义的字段(逻辑主键)还是有意义的字段(业务主键)?个人倾向于“逻辑主键”,理由是这样设计出的数据库模型结构清晰、关系脉络清楚,往往更符合“第三范式”(虽然不是故意的,呵呵)。而且更容易避开“联合主键”,而且可以使用索引效率高的字段类型,比如int、long、number。缺点是用无意义的字段建立表间的关系,使跨表查询增多,效率下降。(矛盾无处不在,前面刚说完可以提高效率,这里马上又降低效率)。“业务主键”可以提升查询编码的简洁度和效率。 个人使用实际状况,总体来说“逻辑主键”比“业务主键”执行效率低,但不会低到无法满足需求。采用“逻辑主键”比采用“业务主键”更利于数据库模型的结构、关系清晰,也更便于维护。 对于分析型数据库,如数据仓库,千万不要这样做。 3.不要使用多对多关系?个人倾向于少使用多对多关系。这个问题其实不是数据库设计的问题了,在数据库设计中,多对多关系也仅仅存在于概念模型(E-R)阶段,物理模型不在有多对多关系,实际数据库中也不会有“多对多”关系。这是使用ORM时的问题,比如使用Hibernate,多对多关系有时会使编码看起来灵活一些,代价是效率的明显降低。 个人实际使用中,设计时基本不考虑多对多关系,但编码时总会有小组成员使用一些多对多关系,自己建立多对多的ORM,使自己编码方便些,用在数据量小的地方,影响不大。大数据量,则“禁止使用”。 4.为每个表增加一个state字段?我习惯在设计时给每个表设一个state字段,取值0或1,默认值为1,具体业务意义或操作上的意义可以自定义。可以作为一个状态控制字段,如查询、更新、删除条件,单据是否有效(业务单据对应的表会有业务意义上的“有/无效”或“状态”字段,这种情况下,我还是会再加一个state字段),甚至仅仅是控制一条数据是否“有效”(有效的意义你自己定)。在数据迁移(如转入分析用的数据库)时也可能会发挥作用。 5.为每个表设置一些备用字段?没办法,我总是设计不出“完美”的数据表,给每个表加几个备用字段(我一般用字符串型,随你)可以应付“不时之需”,尤其是需要长期维护的、业务可能有临时性变动的系统。 6.尽量不要在一个表中存入其关联表的字段?建议不存!这样做确实可以提高查询效率,但在一个有很多表,并且关联表多的情况下,很难保持数据的一致性!数据库结构也比较糟糕。而且不存,也不会使效率十分低下。 7.不要去直接修改数据库?个人认为这点很重要,当需要修改时,应该先去修改模型,然后同步物理数据库,尤其是团队开发,否则要多做更多的事情来搞定,也可能会引入更多的错误。 本文转自博客园执着的笨蛋的博客,原文链接:数据库设计的一些有效经验,如需转载请自行联系原博主。
一个好的数据库产品不等于就有一个好的应用系统,如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能。一般来讲,在一个MIS系统分析、设计、测试和试运行阶段,因为数据量较小,设计人员和测试人员往往只注意到功能的实现,而很难注意到性能的薄弱之处,等到系统投入实际运行一段时间后,才发现系统的性能在降低,这时再来考虑提高系统性能则要花费更多的人力物力,而整个系统也不可避免的形成了一个打补丁工程。笔者依据多年来设计和使用数据库的经验,提出以下一些设计准则,供同仁们参考。 命名的规范 ---- 不同的数据库产品对对象的命名有不同的要求,因此,数据库中的各种对象的命名、后台程序的代码编写应采用大小写敏感的形式,各种对象命名长度不要超过30个字符,这样便于应用系统适应不同的数据库。 游标(Cursor)的慎用 ---- 游标提供了对特定集合中逐行扫描的手段,一般使用游标逐行遍历数据,根据取出的数据不同条件进行不同的操作。尤其对多表和大表定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等特甚至死机,笔者在某市《住房公积金管理系统》进行日终帐户滚积数计息处理时,对一个10万个帐户的游标处理导致程序进入了一个无限期的等特(后经测算需48个小时才能完成)(硬件环境:Alpha/4000 128Mram ,Sco Unix ,Sybase 11.0),后根据不同的条件改成用不同的UPDATE语句得以在二十分钟之内完成。示例如下: Declare Mycursor cursor for select count_no from COUNT Open Mycursor Fetch Mycursor into @vcount_no While (@@sqlstatus=0) Begin If @vcount_no=’’ 条件1 操作1 If @vcount_no=’’ 条件2 操作2 。。。 Fetch Mycursor into @vcount_no End 。。。 。。。 改为 Update COUNT set 操作1 for 条件1 Update COUNT set 操作2 for 条件2 。。。 。。。 ---- 在有些场合,有时也非得使用游标,此时也可考虑将符合条件的数据行转入临时表中,再对临时表定义游标进行操作,可时性能得到明显提高。笔者在某地市〈电信收费系统〉数据库后台程序设计中,对一个表(3万行中符合条件的30多行数据)进行游标操作(硬件环境:PC服务器,PII266 64Mram ,NT4.0 Ms Sqlserver 6.5)。 示例如下: Create #tmp /* 定义临时表 */ (字段1 字段2 。。。 ) Insert into #tmp select * from TOTAL where 条件 /* TOTAL中3万行 符合条件只有几十行 */ Declare Mycursor cursor for select * from #tmp /*对临时表定义游标*/ 。。。 索引(Index)的使用原则 ---- 创建索引一般有以下两个目的:维护被索引列的唯一性和提供快速访问表中数据的策略。大型数据库有两种索引即簇索引和非簇索引,一个没有簇索引的表是按堆结构存储数据,所有的数据均添加在表的尾部,而建立了簇索引的表,其数据在物理上会按照簇索引键的顺序存储,一个表只允许有一个簇索引,因此,根据B树结构,可以理解添加任何一种索引均能提高按索引列查询的速度,但会降低插入、更新、删除操作的性能,尤其是当填充因子(Fill Factor)较大时。所以对索引较多的表进行频繁的插入、更新、删除操作,建表和索引时因设置较小的填充因子,以便在各数据页中留下较多的自由空间,减少页分割及重新组织的工作。 数据的一致性和完整性 ---- 为了保证数据库的一致性和完整性,设计人员往往会设计过多的表间关联(Relation),尽可能的降低数据的冗余。表间关联是一种强制性措施,建立后,对父表(Parent Table)和子表(Child Table)的插入、更新、删除操作均要占用系统的开销,另外,最好不要用Identify 属性字段作为主键与子表关联。如果数据冗余低,数据的完整性容易得到保证,但增加了表间连接查询的操作,为了提高系统的响应时间,合理的数据冗余也是必要的。使用规则(Rule)和约束(Check)来防止系统操作人员误输入造成数据的错误是设计人员的另一种常用手段,但是,不必要的规则和约束也会占用系统的不必要开销,需要注意的是,约束对数据的有效性验证要比规则快。所有这些,设计人员在设计阶段应根据系统操作的类型、频度加以均衡考虑。 事务的陷阱 ---- 事务是在一次性完成的一组操作。虽然这些操作是单个的操作,SQL Server能够保证这组操作要么全部都完成,要么一点都不做。正是大型数据库的这一特性,使得数据的完整性得到了极大的保证。 ---- 众所周知,SQL Server为每个独立的SQL语句都提供了隐含的事务控制,使得每个DML的数据操作得以完整提交或回滚,但是SQL Server还提供了显式事务控制语句 ---- BEGIN TRANSACTION 开始一个事务 ---- COMMIT TRANSACTION 提交一个事务 ---- ROLLBACK TRANSACTION 回滚一个事务 ---- 事务可以嵌套,可以通过全局变量@@trancount检索到连接的事务处理嵌套层次。需要加以特别注意并且极容易使编程人员犯错误的是,每个显示或隐含的事物开始都使得该变量加1,每个事务的提交使该变量减1,每个事务的回滚都会使得该变量置0,而只有当该变量为0时的事务提交(最后一个提交语句时),这时才把物理数据写入磁盘。 数据库性能调整 ---- 在计算机硬件配置和网络设计确定的情况下,影响到应用系统性能的因素不外乎为数据库性能和客户端程序设计。而大多数数据库设计员采用两步法进行数据库设计:首先进行逻辑设计,而后进行物理设计。数据库逻辑设计去除了所有冗余数据,提高了数据吞吐速度,保证了数据的完整性,清楚地表达数据元素之间的关系。而对于多表之间的关联查询(尤其是大数据表)时,其性能将会降低,同时也提高了客 户端程序的编程难度,因此,物理设计需折衷考虑,根据业务规则,确定对关联表的数据量大小、数据项的访问频度,对此类数据表频繁的关联查询应适当提高数据冗余设计。 数据类型的选择 ---- 数据类型的合理选择对于数据库的性能和操作具有很大的影响,有关这方面的书籍也有不少的阐述,这里主要介绍几点经验。 Identify字段不要作为表的主键与其它表关联,这将会影响到该表的数据迁移。 Text 和Image字段属指针型数据,主要用来存放二进制大型对象(BLOB)。这类数据的操作相比其它数据类型较慢,因此要避开使用。 日期型字段的优点是有众多的日期函数支持,因此,在日期的大小比较、加减操作上非常简单。但是,在按照日期作为条件的查询操作也要用函数,相比其它数据类型速度上就慢许多,因为用函数作为查询的条件时,服务器无法用先进的性能策略来优化查询而只能进行表扫描遍历每行。 ---- 例如:要从DATA_TAB1中(其中有一个名为DATE的日期字段)查询1998年的所有记录。 ---- Select * from DATA_TAB1 where datepart(yy,DATE)=1998 本文转自博客园执着的笨蛋的博客,原文链接:大型数据库设计原则,如需转载请自行联系原博主。
数据库设计理论 一、 数据库设计的几个原则 一个好的数据库产品不等于就是一个好的应用系统,如果不能设计一个合理的数据库模型,不仅会增加客户端与服务器端的编程和维护难度,而且会影响系统实际运行的性能。因此,要想开发出一款理想的数据库产品应遵循以下设计准则: (1) 命名规范化 不同的数据库产品对对象的命名有不同的要求。数据库中的各种对象的命名以及后台程序的代码编写应采用大小写敏感的字母形式,各种对象命名长度不要超过30个字符,这样便于应用系统适应不同的数据库。 (2) 慎用游标(Cursor) 对多表和大表定义的游标(大的数据集合)而言,使用游标逐行遍历数据很容易使程序进入漫长的等待甚至死机,因此在使用游标时,可以考虑建立一个临时表,将符合条件的数据行转入临时表中,再对临时表定义游标进行操作,这时性能会得到明显提高。 (3) 索引(Index)的使用 索引一般用于快速访问表中的数据。大型数据库有两种索引,即簇索引和非簇索引。添加任何一种索引均能提高按索引列查询的速度,但会降低插入、更新、删除操作的性能,尤其是当填充因子(Fill Factor)较大时。所以,如果要对索引较多的表进行频繁的插入、更新、删除操作,建立表和索引时应该设置较小的填充因子,以便在各项数据页中留下较多的自由空间,减少页分割及重新重新组织的工作,这样才能够提高性能。 (4) 数据的一致性和完整性 为了保证数据库的一致性和完整性,设计人员往往会设计过多的表间关联,尽可能地降低数据的冗余。但是,表间关联是一种强制性措施,建立后,对父表和子表的插入、更新、删除操作均要占用系统的开销。此外,最好不要用Identify属性字段作为主键与子表关联。如果数据冗余低,数据的完整性容易得到保证,但增加了表间连接查询的操作,因此,为了提高系统的响应时间,合理的数据冗余也是必要的。 (5) 事务的使用 事务是必须一次性完成的一组操作。虽然这些操作是单个的操作,但数据库系统能够保证这组操作要么全部都完成,要么一点都不做。正是大型数据库的这一特性,使得数据的完整性得到了极大的保证。 (6) 数据库性能调整 在计算机硬件配置和网络设计确定的情况下,影响到应用系统性能的因素主要是数据库性能和客户端程序设计。大多数数据库设计员采用两步法进行数据库设计:首先进行逻辑设计,而后进行物理设计。数据库逻辑设计去除了所有冗余数据,提高了数据吞吐速度,保证了数据的完整性,清楚地表达数据元素之间的关系。而对于多表之间的关联查询(尤其是大数据表)时,其性能将会降低,同时也提高了客户端程序的编程难度,因此,物理设计需折中考虑,根据业务规则,确定关联表的数据量大小、数据项的访问频度,对此类数据表频繁的关联查询应适当提高数据冗余设计。 (7) 数据类型的选择 数据类型的合理选择对于数据库的性能和操作具有很大的影响。 ? Identify字段不要作为表的主键与其他表关联,这将会影响到该表的数据迁移。 ? Text和Image字段属指针型数据,主要用来存放二进制大型对象(BLOB)。这类数据的操作相比其他数据类型较慢,因此要避开使用。 ? 日期型字段的优点是有众多的日期函数支持,因此,在日期的大小比较、加减操作上非常简单。但是,按照日期作为条件的查询操作也要用函数,相比其他数据类型在速度上就慢许多。这是因为用函数作为查询的条件时,服务器无法用先进的性能策略来优化查询,只能进行表扫描遍历每行。 二、 数据库设计的基本步骤 对于数据库设计来说,比较统一的看法是分为5个步骤:需求分析,概念结构设计,逻辑结构设计,物理设计,数据实施和维护。 1. 需求分析 要设计一个良好的数据库系统,首先要明确应用环境对系统的要求。因此,对应用环境的需求收集和分析就是数据库设计的第一步。需求阶段收集到的基础数据和一组数据流程图是进行下一步概念设计的基础。需求分析包括以下几个方面: (1) 收集资料 收集资料是数据库设计人员和用户共同完成的任务。强调各级用户的参与是数据库应用系统设计的特点之一。 (2) 分析整理 在大量资料收集完成以后,就要对资料进行分析和整理。分析的过程是对所收集到的数据进行抽象的过程。 (3) 数据流程图 在系统分析中通常采用数据流程图(Data Flow Diagram)来描述系统的数据流向和对数据的处理功能。 (4) 数据字典(Data Dictionary) 除了一套数据流程图外,还要从原始的数据资料中分析整理出下述数据信息:数据元素的名称、同义词、性质、取值范围、提供者、使用者、控制权限、保密要求、使用频率、数据量、数据之间联系的语义说明、各个部门对数据的要求以及数据处理要求。 (5) 用户确认 数据流程图集和数据字典的内容必须返回给用户,并且用非专业术语与用户交流。 需求分析阶段的成果要形成文档资料,至少包括各项业务的数据流程图及有关说明和对各类数据描述的集合,即数据字典。 2. 概念结构设计 将需求分析得到的用户需求抽象为信息结构设计及概念模型的过程就是概念结构设计,它是整个数据库设计的关键。概念建模的过程包括定义实体集、定义联系和定义属性。当这3种成分确定之后,就可以用E-R方法来进行数据库的概念设计。在设计完全局的E-R图之后,要尽量消除冗余。 3. 逻辑结构设计 数据库逻辑设计的任务是将概念结构设计阶段设计好的基本E-R图,转换成特定DBMS所支持的数据模型的过程。这样开始进入“实现设计”,需要考虑具体DBMS的性能,具体的数据模型特点。逻辑设计可分为E-R图向关系模型的转化、数据模型的优化和设计用户子模式3个过程。 4. 物理设计 对于给定的逻辑数据模型选取一个最适合应用环境的物理结构的过程,称为数据库物理设计。数据库的物理设计通常分为两步:确定数据库的物理结构,在关系数据库中主要指存取方法与存储结构:对物理结构进行评价,评价的重点的时间和空间效率。 5. 数据库的实施和维护 数据库的实施和维护过程可分数据的载入和应用程序的调试、数据库的试运行和数据库的维护与运行。 本文转自博客园执着的笨蛋的博客,原文链接:数据库设计理论,如需转载请自行联系原博主。
数据库表结构设计方法及原则 Author: Chancey 在目前的企业信息系统中,数据库还是最佳的数据存储方式,虽然已经有很多的书籍在指导我们进行数据库设计,但应该那种方式是设计数据库的表结构的最好方法、设计时应遵从什么样的原则、四个范式如何能够用一种方式达到顺畅的应用等是我一直在思考和总结的问题,下文是我针对这几个问题根据自己的设计经历准备总结的一篇文章的提纲,欢迎大家一块进行探讨,集思广益。其中提到了领域建模的概念,但未作详细解释,希望以后能够有时间我们针对这个命题进行深入探讨。 1)不应该针对整个系统进行数据库设计,而应该根据系统架构中的组件划分,针对每个组件所处理的业务进行组件单元的数据库设计;不同组件间所对应的数据库表之间的关联应尽可能减少,如果不同组件间的表需要外键关联也尽量不要创建外键关联,而只是记录关联表的一个主键,确保组件对应的表之间的独立性,为系统或表结构的重构提供可能性。 2)采用领域模型驱动的方式和自顶向下的思路进行数据库设计,首先分析系统业务,根据职责定义对象。对象要符合封装的特性,确保与职责相关的数据项被定义在一个对象之内,这些数据项能够完整描述该职责,不会出现职责描述缺失。并且一个对象有且只有一项职责,如果一个对象要负责两个或两个以上的职责,应进行分拆。 3)根据建立的领域模型进行数据库表的映射,此时应参考数据库设计第二范式:一个表中的所有非关键字属性都依赖于整个关键字。关键字可以是一个属性,也可以是多个属性的集合,不论那种方式,都应确保关键字能够保证唯一性。在确定关键字时,应保证关键字不会参与业务且不会出现更新异常,这时,最优解决方案为采用一个自增数值型属性或一个随机字符串作为表的关键字。 4)由于第一点所述的领域模型驱动的方式设计数据库表结构,领域模型中的每一个对象只有一项职责,所以对象中的数据项不存在传递依赖,所以,这种思路的数据库表结构设计从一开始即满足第三范式:一个表应满足第二范式,且属性间不存在传递依赖。 5)同样,由于对象职责的单一性以及对象之间的关系反映的是业务逻辑之间的关系,所以在领域模型中的对象存在主对象和从对象之分,从对象是从1-N或N-N的角度进一步主对象的业务逻辑,所以从对象及对象关系映射为的表及表关联关系不存在删除和插入异常。 6)在映射后得出的数据库表结构中,应再根据第四范式进行进一步修改,确保不存在多值依赖。这时,应根据反向工程的思路反馈给领域模型。如果表结构中存在多值依赖,则证明领域模型中的对象具有至少两个以上的职责,应根据第一条进行设计修正。第四范式:一个表如果满足BCNF,不应存在多值依赖。 7)在经过分析后确认所有的表都满足二、三、四范式的情况下,表和表之间的关联尽量采用弱关联以便于对表字段和表结构的调整和重构。并且,我认为数据库中的表是用来持久化一个对象实例在特定时间及特定条件下的状态的,只是一个存储介质,所以,表和表之间也不应用强关联来表述业务(数据间的一致性),这一职责应由系统的逻辑层来保证,这种方式也确保了系统对于不正确数据(脏数据)的兼容性。当然,从整个系统的角度来说我们还是要尽最大努力确保系统不会产生脏数据,单从另一个角度来说,脏数据的产生在一定程度上也是不可避免的,我们也要保证系统对这种情况的容错性。这是一个折中的方案。 8)应针对所有表的主键和外键建立索引,有针对性的(针对一些大数据量和常用检索方式)建立组合属性的索引,提高检索效率。虽然建立索引会消耗部分系统资源,但比较起在检索时搜索整张表中的数据尤其时表中的数据量较大时所带来的性能影响,以及无索引时的排序操作所带来的性能影响,这种方式仍然是值得提倡的。 9)尽量少采用存储过程,目前已经有很多技术可以替代存储过程的功能如“对象/关系映射”等,将数据一致性的保证放在数据库中,无论对于版本控制、开发和部署、以及数据库的迁移都会带来很大的影响。但不可否认,存储过程具有性能上的优势,所以,当系统可使用的硬件不会得到提升而性能又是非常重要的质量属性时,可经过平衡考虑选用存储过程。 10)当处理表间的关联约束所付出的代价(常常是使用性上的代价)超过了保证不会出现修改、删除、更改异常所付出的代价,并且数据冗余也不是主要的问题时,表设计可以不符合四个范式。四个范式确保了不会出现异常,但也可能由此导致过于纯洁的设计,使得表结构难于使用,所以在设计时需要进行综合判断,但首先确保符合四个范式,然后再进行精化修正是刚刚进入数据库设计领域时可以采用的最好办法。 11)设计出的表要具有较好的使用性,主要体现在查询时是否需要关联多张表且还需使用复杂的SQL技巧。 12)设计出的表要尽可能减少数据冗余,确保数据的准确性,有效的控制冗余有助于提高数据库的性能。 本文转自博客园执着的笨蛋的博客,原文链接:数据库表结构设计方法及原则,如需转载请自行联系原博主。
代码: <SCRIPT>function Refresh(){ Time.innerHTML=new Date().toLocaleString()+' 星期'+'日一二三四五六'.charAt(new Date().getDay()); setTimeout("Refresh()",1000);}var timer=setTimeout("Refresh()",1000);</SCRIPT><DIV style="background-color:#eeeeee" id="Time"></DIV> 本文转自博客园执着的笨蛋的博客,原文链接:js获取 日期 星期 时间,如需转载请自行联系原博主。
方法一: 自己做递归函数 function findChildRecursively(rootNode, key, value) { var nodes = rootNode.childNodes; for(var i = 0; i < nodes.length; i++) { if(nodes[i].attributes[key] == value){ return nodes[i]; } else { if(!nodes[i].isLeaf()) { continue; } if(nodes[i].isLoaded()) { nodes[i].reload(); } if(node = findChildRecursively(nodes[i], key, value)) { return node; } } } return null; } 方法二: 利用现成方法 cascade var node = null; rootNode.cascade(function(n) { if(!n.isLeaf() && !n.isLoaded()) { n.reload(); return true; } if(n.attributes[key] == value) { node = n; return false; } return true; }); 本文转自博客园沉睡森林@漂在北京的博客,原文链接:extjs查找树节点的2种方法,如需转载请自行联系原博主。
conn.prepareCall("{call procedure_name(?,?)}"); 这种调用是用一种换码语法来写的,有两种形式:一种形式带结果参,另一种形式不带结果参数。结果参数是一种输出 (OUT) 参数,是已储存过程的返回值。两种形式都可带有数量可变的输入(IN 参数)、输出(OUT 参数)或输入和输出(INOUT 参数)的参数。问号将用作参数的占位符。 在 JDBC 中调用已储存过程的语法如下所示。注意,方括号表示其间的内容是可选项;方括号本身并非语法的组成部份。 {call 过程名[(?, ?, ...)]} 返回结果参数的过程的语法为: {? = call 过程名[(?, ?, ...)]} 不带参数的已储存过程的语法类似: {call 过程名} 通常,创建 CallableStatement 对象的人应当知道所用的 DBMS 是支持已储存过程的,并且知道这些过程都是些什么。然而,如果需要检查,多种DatabaseMetaData 方法都可以提供这样的信息。例如,如果 DBMS 支持已储存过程的调用,则supportsStoredProcedures 方法将返回 true,而getProcedures 方法将返回对已储存过程的描述。CallableStatement 继承 Statement 的方法(它们用于处理一般的 SQL 语句),还继承了 PreparedStatement 的方法(它们用于处理 IN 参)。 CallableStatement 中定义的所有方法都用于处理 OUT 参数或 INOUT 参数的输出部分:注册 OUT 参数的 JDBC 类型(一般 SQL 类型)、从这些参数中检索结果,或者检查所返回的值是否为 JDBC NULL。 1、创建 CallableStatement 对象 CallableStatement 对象是用 Connection 方法 prepareCall 创建的。下例创建 CallableStatement 的实例,其中含有对已储存过程 getTestData 调用。该过程有两个变量,但不含结果参数: CallableStatement cstmt = con.prepareCall("{call getTestData(?, ?)}"); 其中?占位符为IN、OUT还是INOUT参数,取决于已储存过程getTestData。 2、IN和OUT参数 将IN参数传给 CallableStatement 对象是通过 setXXX 方法完成的。该方法继承自 PreparedStatement。所传入参数的类型决定了所用的setXXX方法(例如,用 setFloat 来传入 float 值等)。 如果已储存过程返回 OUT 参数,则在执行 CallableStatement 对象以前必须先注册每个 OUT 参数的 JDBC 类型(这是必需的,因为某些 DBMS 要求 JDBC 类型)。注册 JDBC 类型是用 registerOutParameter 方法来完成的。语句执行完后,CallableStatement 的 getXXX 方法将取回参数值。正确的 getXXX 方法是为各参数所注册的 JDBC 类型所对应的 Java 类型。换言之, registerOutParameter 使用的是 JDBC 类型(因此它与数据库返回的 JDBC 类型匹配),而 getXXX 将之转换为 Java 类型。 作为示例,下述代码先注册 OUT 参数,执行由 cstmt 所调用的已储存过程,然后检索在 OUT 参数中返回的值。方法 getByte 从第一个 OUT 参数中取出一个 Java 字节,而 getBigDecimal 从第二个 OUT 参数中取出一个 BigDecimal 对象(小数点后面带三位数): CallableStatement cstmt = con.prepareCall("{call getTestData(?, ?)}"); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3); cstmt.executeQuery(); byte x = cstmt.getByte(1); java.math.BigDecimal n = cstmt.getBigDecimal(2, 3); CallableStatement 与 ResultSet 不同,它不提供用增量方式检索大 OUT 值的特殊机制。 3、INOUT参数 既支持输入又接受输出的参数(INOUT 参数)除了调用 registerOutParameter 方法外,还要求调用适当的 setXXX 方法(该方法是从 PreparedStatement 继承来的)。setXXX 方法将参数值设置为输入参数,而 registerOutParameter 方法将它的 JDBC 类型注册为输出参数。setXXX 方法提供一个 Java 值,而驱动程序先把这个值转换为 JDBC 值,然后将它送到数据库中。这种 IN 值的 JDBC 类型和提供给 registerOutParameter 方法的 JDBC 类型应该相同。然后,要检索输出值,就要用对应的 getXXX 方法。例如,Java 类型为byte 的参数应该使用方法 setByte 来赋输入值。应该给registerOutParameter 提供类型为 TINYINT 的 JDBC 类型,同时应使用 getByte 来检索输出值。 下例假设有一个已储存过程 reviseTotal,其唯一参数是 INOUT 参数。方法setByte 把此参数设为 25,驱动程序将把它作为 JDBC TINYINT 类型送到数据库中。接着,registerOutParameter 将该参数注册为 JDBC TINYINT。执行完该已储存过程后,将返回一个新的 JDBC TINYINT 值。方法 getByte 将把这个新值作为 Java byte 类型检索。 CallableStatement cstmt = con.prepareCall("{call reviseTotal(?)}"); cstmt.setByte(1, 25); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.executeUpdate(); byte x = cstmt.getByte(1); 4、先检索结果,再检索 OUT 参数 由于某些 DBMS 的限制,为了实现最大的可移植性,建议先检索由执行CallableStatement 对象所产生的结果,然后再用 CallableStatement.getXXX 方法来检索 OUT 参数。如果 CallableStatement 对象返回多个 ResultSet 对象(通过调用 execute 方法),在检索 OUT 参数前应先检索所有的结果。这种情况下,为确保对所有的结果都进行了访问,必须对 Statement 方法 getResultSet、getUpdateCount 和getMoreResults 进行调用,直到不再有结果为止。 检索完所有的结果后,就可用 CallableStatement.getXXX 方法来检索 OUT 参数中的值。 5、检索作为OUT参数的NULL值 返回到 OUT 参数中的值可能会是JDBC NULL。当出现这种情形时,将对 JDBC NULL 值进行转换以使 getXXX 方法所返回的值为 null、0 或 false,这取决于getXXX 方法类型。对于 ResultSet 对象,要知道0或false是否源于JDBCNULL的唯一方法,是用方法wasNull进行检测。如果 getXXX 方法读取的最后一个值是 JDBC NULL,则该方法返回 true,否则返回 flase。 本文转自博客园执着的笨蛋的博客,原文链接:java执行存储过程,如需转载请自行联系原博主。
Date.prototype.isLeapYear 判断闰年Date.prototype.Format 日期格式化Date.prototype.DateAdd 日期计算Date.prototype.DateDiff 比较日期差Date.prototype.toString 日期转字符串Date.prototype.toArray 日期分割为数组Date.prototype.DatePart 取日期的部分信息Date.prototype.MaxDayOfDate 取日期所在月的最大天数Date.prototype.WeekNumOfYear 判断日期所在年的第几周StringToDate 字符串转日期型IsValidDate 验证日期有效性CheckDateTime 完整日期时间检查daysBetween 日期天数差js代码: //--------------------------------------------------- // 判断闰年 //--------------------------------------------------- Date.prototype.isLeapYear = function() { return (0==this.getYear()%4&&((this.getYear()%100!=0)||(this.getYear()%400==0))); } //--------------------------------------------------- // 日期格式化 // 格式 YYYY/yyyy/YY/yy 表示年份 // MM/M 月份 // W/w 星期 // dd/DD/d/D 日期 // hh/HH/h/H 时间 // mm/m 分钟 // ss/SS/s/S 秒 //--------------------------------------------------- Date.prototype.Format = function(formatStr) { var str = formatStr; var Week = ['日','一','二','三','四','五','六']; str=str.replace(/yyyy|YYYY/,this.getFullYear()); str=str.replace(/yy|YY/,(this.getYear() % 100)>9?(this.getYear() % 100).toString():'0' + (this.getYear() % 100)); str=str.replace(/MM/,this.getMonth()>9?this.getMonth().toString():'0' + this.getMonth()); str=str.replace(/M/g,this.getMonth()); str=str.replace(/w|W/g,Week[this.getDay()]); str=str.replace(/dd|DD/,this.getDate()>9?this.getDate().toString():'0' + this.getDate()); str=str.replace(/d|D/g,this.getDate()); str=str.replace(/hh|HH/,this.getHours()>9?this.getHours().toString():'0' + this.getHours()); str=str.replace(/h|H/g,this.getHours()); str=str.replace(/mm/,this.getMinutes()>9?this.getMinutes().toString():'0' + this.getMinutes()); str=str.replace(/m/g,this.getMinutes()); str=str.replace(/ss|SS/,this.getSeconds()>9?this.getSeconds().toString():'0' + this.getSeconds()); str=str.replace(/s|S/g,this.getSeconds()); return str; } //+--------------------------------------------------- //| 求两个时间的天数差 日期格式为 YYYY-MM-dd //+--------------------------------------------------- function daysBetween(DateOne,DateTwo) { var OneMonth = DateOne.substring(5,DateOne.lastIndexOf ('-')); var OneDay = DateOne.substring(DateOne.length,DateOne.lastIndexOf ('-')+1); var OneYear = DateOne.substring(0,DateOne.indexOf ('-')); var TwoMonth = DateTwo.substring(5,DateTwo.lastIndexOf ('-')); var TwoDay = DateTwo.substring(DateTwo.length,DateTwo.lastIndexOf ('-')+1); var TwoYear = DateTwo.substring(0,DateTwo.indexOf ('-')); var cha=((Date.parse(OneMonth+'/'+OneDay+'/'+OneYear)- Date.parse(TwoMonth+'/'+TwoDay+'/'+TwoYear))/86400000); return Math.abs(cha); } //+--------------------------------------------------- //| 日期计算 //+--------------------------------------------------- Date.prototype.DateAdd = function(strInterval, Number) { var dtTmp = this; switch (strInterval) { case 's' :return new Date(Date.parse(dtTmp) + (1000 * Number)); case 'n' :return new Date(Date.parse(dtTmp) + (60000 * Number)); case 'h' :return new Date(Date.parse(dtTmp) + (3600000 * Number)); case 'd' :return new Date(Date.parse(dtTmp) + (86400000 * Number)); case 'w' :return new Date(Date.parse(dtTmp) + ((86400000 * 7) * Number)); case 'q' :return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) + Number*3, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(), dtTmp.getSeconds()); case 'm' :return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) + Number, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(), dtTmp.getSeconds()); case 'y' :return new Date((dtTmp.getFullYear() + Number), dtTmp.getMonth(), dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(), dtTmp.getSeconds()); } } //+--------------------------------------------------- //| 比较日期差 dtEnd 格式为日期型或者 有效日期格式字符串 //+--------------------------------------------------- Date.prototype.DateDiff = function(strInterval, dtEnd) { var dtStart = this; if (typeof dtEnd == 'string' )//如果是字符串转换为日期型 { dtEnd = StringToDate(dtEnd); } switch (strInterval) { case 's' :return parseInt((dtEnd - dtStart) / 1000); case 'n' :return parseInt((dtEnd - dtStart) / 60000); case 'h' :return parseInt((dtEnd - dtStart) / 3600000); case 'd' :return parseInt((dtEnd - dtStart) / 86400000); case 'w' :return parseInt((dtEnd - dtStart) / (86400000 * 7)); case 'm' :return (dtEnd.getMonth()+1)+((dtEnd.getFullYear()-dtStart.getFullYear())*12) - (dtStart.getMonth()+1); case 'y' :return dtEnd.getFullYear() - dtStart.getFullYear(); } } //+--------------------------------------------------- //| 日期输出字符串,重载了系统的toString方法 //+--------------------------------------------------- Date.prototype.toString = function(showWeek) { var myDate= this; var str = myDate.toLocaleDateString(); if (showWeek) { var Week = ['日','一','二','三','四','五','六']; str += ' 星期' + Week[myDate.getDay()]; } return str; } //+--------------------------------------------------- //| 日期合法性验证 //| 格式为:YYYY-MM-DD或YYYY/MM/DD //+--------------------------------------------------- function IsValidDate(DateStr) { var sDate=DateStr.replace(/(^\s+|\s+$)/g,''); //去两边空格; if(sDate=='') return true; //如果格式满足YYYY-(/)MM-(/)DD或YYYY-(/)M-(/)DD或YYYY-(/)M-(/)D或YYYY-(/)MM-(/)D就替换为'' //数据库中,合法日期可以是:YYYY-MM/DD(2003-3/21),数据库会自动转换为YYYY-MM-DD格式 var s = sDate.replace(/[\d]{ 4,4 }[\-/]{ 1 }[\d]{ 1,2 }[\-/]{ 1 }[\d]{ 1,2 }/g,''); if (s=='') //说明格式满足YYYY-MM-DD或YYYY-M-DD或YYYY-M-D或YYYY-MM-D { var t=new Date(sDate.replace(/\-/g,'/')); var ar = sDate.split(/[-/:]/); if(ar[0] != t.getYear() || ar[1] != t.getMonth()+1 || ar[2] != t.getDate()) { //alert('错误的日期格式!格式为:YYYY-MM-DD或YYYY/MM/DD。注意闰年。'); return false; } } else { //alert('错误的日期格式!格式为:YYYY-MM-DD或YYYY/MM/DD。注意闰年。'); return false; } return true; } //+--------------------------------------------------- //| 日期时间检查 //| 格式为:YYYY-MM-DD HH:MM:SS //+--------------------------------------------------- function CheckDateTime(str) { var reg = /^(\d+)-(\d{ 1,2 })-(\d{ 1,2 }) (\d{ 1,2 }):(\d{ 1,2 }):(\d{ 1,2 })$/; var r = str.match(reg); if(r==null)return false; r[2]=r[2]-1; var d= new Date(r[1],r[2],r[3],r[4],r[5],r[6]); if(d.getFullYear()!=r[1])return false; if(d.getMonth()!=r[2])return false; if(d.getDate()!=r[3])return false; if(d.getHours()!=r[4])return false; if(d.getMinutes()!=r[5])return false; if(d.getSeconds()!=r[6])return false; return true; } //+--------------------------------------------------- //| 把日期分割成数组 //+--------------------------------------------------- Date.prototype.toArray = function() { var myDate = this; var myArray = Array(); myArray[0] = myDate.getFullYear(); myArray[1] = myDate.getMonth(); myArray[2] = myDate.getDate(); myArray[3] = myDate.getHours(); myArray[4] = myDate.getMinutes(); myArray[5] = myDate.getSeconds(); return myArray; } //+--------------------------------------------------- //| 取得日期数据信息 //| 参数 interval 表示数据类型 //| y 年 m月 d日 w星期 ww周 h时 n分 s秒 //+--------------------------------------------------- Date.prototype.DatePart = function(interval) { var myDate = this; var partStr=''; var Week = ['日','一','二','三','四','五','六']; switch (interval) { case 'y' :partStr = myDate.getFullYear();break; case 'm' :partStr = myDate.getMonth()+1;break; case 'd' :partStr = myDate.getDate();break; case 'w' :partStr = Week[myDate.getDay()];break; case 'ww' :partStr = myDate.WeekNumOfYear();break; case 'h' :partStr = myDate.getHours();break; case 'n' :partStr = myDate.getMinutes();break; case 's' :partStr = myDate.getSeconds();break; } return partStr; } //+--------------------------------------------------- //| 取得当前日期所在月的最大天数 //+--------------------------------------------------- Date.prototype.MaxDayOfDate = function() { var myDate = this; var ary = myDate.toArray(); var date1 = (new Date(ary[0],ary[1]+1,1)); var date2 = date1.dateAdd(1,'m',1); var result = dateDiff(date1.Format('yyyy-MM-dd'),date2.Format('yyyy-MM-dd')); return result; } //+--------------------------------------------------- //| 取得当前日期所在周是一年中的第几周 //+--------------------------------------------------- Date.prototype.WeekNumOfYear = function() { var myDate = this; var ary = myDate.toArray(); var year = ary[0]; var month = ary[1]+1; var day = ary[2]; document.write('< script language=VBScript\> \n'); document.write('myDate = DateValue(''+month+'-'+day+'-'+year+'') \n'); document.write('result = DatePart('ww', myDate) \n'); document.write(' \n'); return result; } //+--------------------------------------------------- //| 字符串转成日期类型 //| 格式 MM/dd/YYYY MM-dd-YYYY YYYY/MM/dd YYYY-MM-dd //+--------------------------------------------------- function StringToDate(DateStr) { var converted = Date.parse(DateStr); var myDate = new Date(converted); if (isNaN(myDate)) { //var delimCahar = DateStr.indexOf('/')!=-1?'/':'-'; var arys= DateStr.split('-'); myDate = new Date(arys[0],--arys[1],arys[2]); } return myDate; } 本文转自博客园执着的笨蛋的博客,原文链接:[转]js日期时间函数(经典+完善+实用),如需转载请自行联系原博主。
--根据FILE_ID & BLOCK_ID获得对象名称SELECT /*+ RULE*/ owner, segment_name, segment_type FROM dba_extents WHERE file_id = &file_id AND &block_id BETWEEN block_id AND block_id + blocks - 1;--根据操作系统PID,查询SESSION信息SELECT a.sid, a.serial#, b.spid, a.terminal, a.machine, a.program, a.osuser FROM v$session a, v$process b WHERE a.paddr = b.addr AND b.spid = '&SPID';--根据SESSION SID,查询操作系统PIDSELECT a.sid, a.serial#, b.spid, a.terminal, a.machine, a.program, a.osuser FROM v$session a, v$process b WHERE a.paddr = b.addr AND a.sid = '&SID';--查询用户正在执行的SQLSELECT sql_text FROM v$sqltext WHERE hash_value = (SELECT sql_hash_value FROM v$session WHERE sid = &sid) ORDER BY piece;--查询当前的系统等待事件SELECT * FROM v$session_wait WHERE event NOT LIKE '%SQL*Net%' AND event NOT LIKE '%rdbms%' AND event NOT LIKE '%timer%' AND event NOT LIKE '%jobq%' ORDER BY event, seconds_in_wait;--查询详细的当前系统等待事件SELECT s.sid, s.username, w.seq#, w.event, w.p1text, w.p1, w.p2text, w.p2, w.p3text, w.p3, w.seconds_in_wait, w.state, s.logon_time, s.osuser, s.program FROM v$session s, v$session_wait w WHERE s.sid = w.sid AND w.event NOT LIKE '%SQL*Net%' AND w.event NOT LIKE '%rdbms%' AND w.event NOT LIKE '%timer%' AND w.event NOT LIKE '%jobq%' ORDER BY w.event, w.seconds_in_wait;--查询等待db file sequential/scattered read的Session正在执行的SQLSELECT s.sid, s.username, t.hash_value, t.piece, t.sql_text FROM v$session s, v$session_wait w, v$sqltext t WHERE s.sid = w.sid AND s.sql_hash_value = t.hash_value AND w.event IN ('db file sequential read', 'db file scattered read') ORDER BY s.sid, t.piece;--查询等待db file sequential/scattered read对应的数据库对象SELECT /*+ RULE*/ s.sid, s.username, w.seq#, w.event, d.segment_type, d.owner || '.' || d.segment_name AS segment_name, w.seconds_in_wait, w.state, s.logon_time FROM v$session s, v$session_wait w, dba_extents d WHERE s.sid = w.sid AND d.file_id = w.p1 AND w.p2 BETWEEN d.block_id AND d.block_id + d.blocks - 1 AND w.event IN ('db file sequential read', 'db file scattered read') ORDER BY w.event, segment_name;--查询导致LOCK的SID,SPID,LOCKED_OBJECT,LOCK_TYPE等信息SELECT /*+ RULE*/ l.sid, p.spid, s.username,s.logon_time, s.osuser, s.program, l.type, CASE l.TYPE WHEN 'TM' THEN O.object_name WHEN 'TX' THEN '' END as OBJECT_NAME, DECODE (l.lmode, 0, '0=NONE', 1, '1=NULL', 2, '2=RS', 3, '3=RX', 4, '4=S', 5, '5=SRX', 6, '6=X') lmode, CASE l.request WHEN 0 THEN '' ELSE 'BLOCKED BY ' || l.id2 END as BLOCKED, CASE l.block WHEN 0 THEN '' ELSE l.id2 || ' IS BLOCKING' END as BLOCKING, l.request, l.ctime FROM v$lock l, v$session s, dba_objects o, v$process p WHERE l.type in ('TX', 'TM') AND s.paddr = p.addr AND l.sid = s.sid AND l.id1 = o.object_id(+) ORDER BY s.username, l.sid, l.ctime;--查询导致DDL LOCK的详细信息SELECT s.sid, p.spid, s.username, a.owner || '.' || a.NAME AS OBJECT_NAME, a.TYPE, a.mode_held, a.mode_requested, s.osuser, s.logon_time, s.program FROM dba_ddl_locks a, v$session s, v$process p WHERE s.sid = a.session_id AND s.paddr = p.addr AND (a.mode_held = 'Exclusive' OR a.mode_requested = 'Exclusive') ORDER BY s.USERNAME, a.NAME;--查询事务使用的回滚段SELECT s.username, s.sid, s.serial#, t.ubafil "UBA filenum", t.ubablk "UBA Block number", t.used_ublk "Number of undo Blocks Used", t.start_time, t.status, t.start_scnb, t.xidusn rollid, r.name rollname FROM v$session s, v$transaction t, v$rollname r WHERE s.saddr = t.ses_addr AND t.xidusn = r.usn;####################################################################################################--查询LIBRARY CACHE PIN等待事件等待的对象--视图缩写:[K]ernel [G]eneric [L]ibrary Cache Manager [OB]jectSELECT /*+ RULE*/ addr, kglhdadr, kglhdpar, kglnaobj, kglnahsh, kglhdobj FROM x$kglob WHERE kglhdadr IN (SELECT p1raw FROM v$session_wait WHERE event LIKE '%library%');--查询LIBRARY CACHE PIN等待事件中持有被等待对象的SESSION信息--视图缩写:[K]ernel [G]eneric [L]ibrary Cache Manager Object [P]i[N]sSELECT /*+ RULE*/ a.SID, a.username, a.program, b.addr, b.kglpnadr, b.kglpnuse, b.kglpnses, b.kglpnhdl, b.kglpnlck, b.kglpnmod, b.kglpnreq FROM v$session a, x$kglpn b WHERE a.saddr = b.kglpnuse AND b.kglpnmod <> 0 AND b.kglpnhdl IN (SELECT p1raw FROM v$session_wait WHERE event LIKE '%library%');--查询LIBRARY CACHE PIN等待事件中持有被等待对象的SESSION执行的SQL语句SELECT sql_text FROM v$sqlarea WHERE (v$sqlarea.address, v$sqlarea.hash_value) IN ( SELECT sql_address, sql_hash_value FROM v$session WHERE SID IN ( SELECT /*+ RULE*/ SID FROM v$session a, x$kglpn b WHERE a.saddr = b.kglpnuse AND b.kglpnmod <> 0 AND b.kglpnhdl IN (SELECT p1raw FROM v$session_wait WHERE event LIKE '%library%')));--查询哪个SESSION正在使用某个对象(LIBRARY CACHE)SELECT DISTINCT s.sid, s.username, s.logon_time, s.osuser, s.program, b.kglnahsh as SQL_HASH_VALUE, b.kglnaobj as SQL_TEXT FROM v$session s, x$kglpn n, x$kglob b WHERE n.kglpnuse = s.saddr AND upper(b.kglnaobj) LIKE upper('%&OBJECT_NAME%') AND n.kglpnhdl = b.kglhdadr;--查询V$SESSION_WAIT用户PIN住了哪些对象(LIBRARY CACHE)SELECT DISTINCT s.sid, s.username, s.logon_time, s.osuser, s.program, n.kglpnmod, b.kglnahsh AS SQL_HASH_VALUE, b.kglnaobj AS SQL_TEXT FROM v$session s, x$kglpn n, x$kglob b WHERE n.kglpnuse = s.saddr AND n.kglpnhdl = b.kglhdadr AND s.sid IN (SELECT sid FROM v$session_wait WHERE event NOT LIKE '%SQL*Net%' AND event NOT LIKE '%rdbms%' AND event NOT LIKE '%timer%' AND event NOT LIKE '%jobq%') ORDER BY s.username;--查询哪些大对象被载入SHARED POOL时导致其它对象被老化SELECT s.sid, s.username, s.logon_time, s.osuser, s.program, k.ksmlrcom, k.ksmlrsiz, k.ksmlrnum, k.ksmlrhon, k.ksmlrses FROM x$ksmlru k, v$session s WHERE s.saddr = k.ksmlrses AND ksmlrsiz > 0;####################################################################################################--查询Schema哪些表是全表扫描SELECT o.name, x.tch FROM obj$ o, x$bh x, dba_users u WHERE x.obj = o.dataobj# AND STANDARD.bitand(x.flag, 524288) > 0 AND u.username = UPPER('&username') ORDER BY x.tch DESC;--查询低效率的SQL(BUFFER_GETS排序)SELECT * FROM (SELECT s.sid, b.spid, s.sql_hash_value, q.sql_text, q.executions, q.buffer_gets, ROUND(q.buffer_gets / q.executions) AS buffer_per_exec, ROUND(q.elapsed_time / q.executions) AS cpu_time_per_exec, q.cpu_time, q.elapsed_time, q.disk_reads, q.rows_processed FROM v$session s, v$process b, v$sql q WHERE s.sql_hash_value = q.hash_value AND s.paddr = b.addr AND s.status = 'ACTIVE' AND s.TYPE = 'USER' AND q.buffer_gets > 0 AND q.executions > 0 ORDER BY buffer_per_exec DESC) WHERE ROWNUM <= 10;####################################################################################################--监控BufferCache命中率SELECT a.value + b.value logical_reads, c.value phys_reads, ROUND (100 * (1 - c.value / (a.value + b.value)), 4) hit_ratio FROM v$sysstat a, v$sysstat b, v$sysstat c WHERE a.NAME = 'db block gets' AND b.NAME = 'consistent gets' AND c.NAME = 'physical reads';--监控LibraryCache命中率SELECT SUM (pins) total_pins, SUM (reloads) total_reloads, SUM (reloads) / SUM (pins) * 100 libcache_reload_ratio FROM v$librarycache;--查询产生的跟踪文件名SELECT p1.VALUE || '/' || p2.VALUE || '_ora_' || p.spid || '.trc' filename FROM v$process p, v$session s, v$parameter p1, v$parameter p2 WHERE p1.NAME = 'user_dump_dest' AND p2.NAME = 'db_name' AND p.addr = s.paddr AND s.audsid = USERENV ('SESSIONID');--删除表中的重复记录DELETE FROM table_name a WHERE ROWID > (SELECT MIN (ROWID) FROM table_name b WHERE b.pk_column_1 = a.pk_column_1 AND b.pk_column_2 = a.pk_column_2); 本文转自博客园沉睡森林@漂在北京的博客,原文链接:oracle常用的监控语句,如需转载请自行联系原博主。
什么是savepoint?Use the SAVEPOINT statement to identify a point in a transaction to which you can later roll back.例如: SQL> SELECT * FROM SCOTT.DEPT ;DEPTNO DNAME LOC------ -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTONSQL> UPDATE SCOTT.DEPT SET loc ='a' WHERE loc='NEW YORK';1 row updatedSQL> SAVEPOINT a;Savepoint createdSQL> UPDATE SCOTT.DEPT SET loc ='b' WHERE loc='DALLAS';1 row updatedSQL> SAVEPOINT b;Savepoint createdSQL> ROLLBACK TO SAVEPOINT a;Rollback completeSQL> COMMIT;Commit completeSQL> SELECT * FROM SCOTT.DEPT ;DEPTNO DNAME LOC------ -------------- ------------- 10 ACCOUNTING a 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 事务中的Savepoints 你可以在事务上下文中声明称为savepoint的中间标记。Savepoint将一个长事务分隔为较小的部分。 使用savepoint,你可以在长事务中任何点任意标记你的操作。然后你可以选择回滚在事务中当前点之前、声明的savepoint之后执行的操作。比如,你可以在一长段复杂的更新中使用savepoint,如果犯了个错,你不需要重新提交所有语句。 Savepoints在应用程序中同样有用。如果一个过程包含几个函数,那可以在每个函数前创建一个savepoint。如果一个函数失败,返回数据到函数开始前的状态并在修改参数或执行一个恢复操作后重新运行函数就非常容易。 在回滚到一个savepoint后,Oracle释放由被回滚的语句持有的锁。其他等待之前被锁资源的事务可以进行了。其他要更新之前被锁行的事务也可以执行。 当一个事务回滚到一个savepoint,发生下列事件: 1. Oracle仅回滚savepoint之后的语句。 2. Oracle保留这一savepoint,但所有建立于此后的savepoints丢失。 3. Oracle释放在该savepoint后获得的所有表、行锁,但保留之前获得的所有锁。 事务保持活动并可继续。 无论何时一个会话在等待事务,到savepoint的回滚不会释放行锁。为了确保事务如果无法获得锁也不会悬挂(hang),在执行UPDATE或DELETE前使用FOR UPDATE ... NOWAIT。(这里指回滚的savepoint之前获得的锁。该savepoint后获得的行锁会被释放,之后执行的语句也会被彻底回滚。) 注意:1.savepoint 名字保持唯一2.如果后面新设置的一个savepoint的名字和前面的一个savepoint名字重复,前一个savepoint将被取消3.设置savepoint后,事务可以继续commit,全部回退或者回退到具体一个savepoints(Savepoint names must be distinct within a given transaction. If you create a second savepoint with the same identifier as an earlier savepoint, then the earlier savepoint is erased. After a savepoint has been created, you can either continue processing, commit your work, roll back the entire transaction, or roll back to the savepoint.) 4.撤销的处理必须是在没有发出commit命令的前提下才能有效。如下:在commit;后执行rollback to savepoint失败 SQL> SELECT * FROM SCOTT.DEPT ;DEPTNO DNAME LOC------ -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTONSQL> UPDATE SCOTT.DEPT SET loc ='a' WHERE loc='NEW YORK';1 row updatedSQL> SAVEPOINT a;Savepoint createdSQL> UPDATE SCOTT.DEPT SET loc ='b' WHERE loc='DALLAS';1 row updatedSQL> SAVEPOINT b;Savepoint createdSQL> COMMIT;Commit completeSQL> ROLLBACK TO SAVEPOINT a;ROLLBACK TO SAVEPOINT aORA-01086: 从未创建保留点 'A'SQL> SELECT * FROM SCOTT.DEPT ;DEPTNO DNAME LOC------ -------------- ------------- 10 ACCOUNTING a 20 RESEARCH b 30 SALES CHICAGO 40 OPERATIONS BOSTON 本文转自博客园沉睡森林@漂在北京的博客,原文链接:[转]什么是savepoint?,如需转载请自行联系原博主。
1. 修改当前DBMS(Script\Objects\Column\ColumnComment)位置的值如下: DECLARE @des VARCHAR(255)SET @des = CASE N'%COMMENT%' WHEN N'%Name%' THEN N'%Name%' ELSE N'%Name%'+'('+ N'%COMMENT%' + ')'ENDEXECUTE sp_addextendedproperty N'MS_Description', @des, N'user', N'%OWNER%', N'table', N'%TABLE%', N'column', N'%COLUMN%' 2.PD中添加测试用的字段 性别3.生成SQL语句,生成之后的SQL语句为: /*==============================================================*//* DBMS name: SQL SERVER 2000 [EXT] *//* Created on: 2008-2-28 16:57:43 *//*==============================================================*/if exists (select 1 from sysobjects where id = object_id('dbo.Employee') and type = 'U') drop table dbo.Employeego/*==============================================================*//* Table: Employee *//*==============================================================*/create table dbo.Employee ( ID int not null, Username varchar(20) null, Password varchar(20) null, Sex int null, constraint PK_EMPLOYEE primary key (ID) )goEXECUTE sp_addextendedproperty N'MS_Description', N'Employee', N'user', N'dbo', N'table', N'Employee', NULL, NULLgoDECLARE @des VARCHAR(255)SET @des = CASE N'主键ID' WHEN N'主键ID' THEN N'主键ID' ELSE N'主键ID'+'('+ N'主键ID' + ')'ENDEXECUTE sp_addextendedproperty N'MS_Description', @des , N'user', N'dbo', N'table', N'Employee', N'column', N'ID'goDECLARE @des VARCHAR(255)SET @des = CASE N'用户名' WHEN N'用户名' THEN N'用户名' ELSE N'用户名'+'('+ N'用户名' + ')'ENDEXECUTE sp_addextendedproperty N'MS_Description', @des , N'user', N'dbo', N'table', N'Employee', N'column', N'Username'goDECLARE @des VARCHAR(255)SET @des = CASE N'密码' WHEN N'密码' THEN N'密码' ELSE N'密码'+'('+ N'密码' + ')'ENDEXECUTE sp_addextendedproperty N'MS_Description', @des , N'user', N'dbo', N'table', N'Employee', N'column', N'Password'goDECLARE @des VARCHAR(255)SET @des = CASE N'1 男 0 女' WHEN N'性别' THEN N'性别' ELSE N'性别'+'('+ N'1 男 0 女' + ')'ENDEXECUTE sp_addextendedproperty N'MS_Description', @des , N'user', N'dbo', N'table', N'Employee', N'column', N'Sex'go 最后效果图:注意:本次使用的例子是在上篇文章的基础上进行修改的,包括数据库以及PD配置!! 本文转自博客园农民伯伯的博客,原文链接:PowerDesigner 12 根据名称生成注释(续),如需转载请自行联系原博主。
首先我们需要明白一个道理,不管一个ASPX页面里面装了多少个ASCX,始终还是要生成一个页面的代码的,所以毫无疑问,我觉得在解决这个问题之前我就已经确定这个问题是可解的。直接贴代码了,首先是用户控件调用父页面的方法: //获得父页面 Page p = this.Parent.Page; Type pageType = p.GetType(); //父页面的方法名 MethodInfo mi = pageType.GetMethod("Loading"); //执行 mi.Invoke(p, new object[] { "参数1","参数2" }); 用户控件与用户控件之间调用: //获得父页面 Page p = this.Parent.Page; //获得父页面的子控件 UserControl uc = p.FindControl("tj_ReceiptList2") as UserControl; Type pageType = uc.GetType(); //父类方法名 MethodInfo mi = pageType.GetMethod("Loading"); //参数 mi.Invoke(uc, new object[] { "参数1", "参数2" }); 本文转自博客园农民伯伯的博客,原文链接:关于ASP.NET同页面内【用户控件与父页面】以及【用户控件与用户控件】之间方法调用/传值 一点点经验,如需转载请自行联系原博主。
1、首先设置EhCache,建立配置文件ehcache.XML,默认的位置在class-path,可以放到你的src目录下:<?xml version="1.0" encoding="UTF-8"?><ehcache><diskStore path="Java.io.tmpdir"/> <defaultCachemaxElementsInMemory="10000" <!-- 缓存最大数目 -->eternal="false" <!-- 缓存是否持久 -->overflowToDisk="true" <!-- 是否保存到磁盘,当系统当机时-->timeToIdleSeconds="300" <!-- 当缓存闲置n秒后销毁 -->timeToLiveSeconds="180" <!-- 当缓存存活n秒后销毁-->diskPersistent="false"diskExpiryThreadIntervalSeconds= "120"/> </ehcache> 2、在Hibernate配置文件中设置:<!-- 设置Hibernate的缓存接口类,这个类在Hibernate包中 --><property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> <!-- 是否使用查询缓存 --><property name="hibernate.cache.use_query_cache">true</property>如果使用spring调用Hibernate的sessionFactory的话,这样设置:<!--HibernateSession工厂管理 --><bean id="sessionFactory" class="org.springFramework.orm.hibernate3.LocalSessionFactoryBean"><property name="dataSource"><ref bean="datasource" /></property><property name="hibernateProperties"><props><prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop><prop key="connection.provider_class"> org.hibernate.connection.C3P0ConnectionProvider </prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.cache.use_query_cache">true</prop><prop key="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </prop></props></property><property name="mappingDirectoryLocations"><list><value>/Web-INF/classes/cn/rmic/manager/hibernate/</value></list></property> </bean> 说明一下:如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置hibernate.cache.use_query_cache true才行。3、在Hbm文件中添加<cache usage="read-only"/>4、如果需要“查询缓存”,还需要在使用Query或Criteria()时设置其setCacheable(true);属性5、实践出真知,给一段测试程序,如果成功的话第二次查询时不会读取数据库package cn.rmic.hibernatesample;import java.util.List;import org.hibernate.CacheMode;import org.hibernate.Criteria;import org.hibernate.Query;import org.hibernate.Session;import cn.rmic.hibernatesample.hibernate.HibernateSessionFactory;import cn.rmic.manager.po.Resources;public class testCacheSelectList {/** *//*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubSession s=HibernateSessionFactory.getSession();Criteria c=s.createCriteria(Resources.class);c.setCacheable(true);List l=c.list();// Query q=s.createQuery("From Resources r")// .setCacheable(true) // .setCacheRegion("frontpages") ;// List l=q.list();Resources resources=(Resources)l.get(0);System.out.println("-1-"+resources.getName());HibernateSessionFactory.closeSession();try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}s=HibernateSessionFactory.getSession();c=s.createCriteria(Resources.class);c.setCacheable(true);l=c.list();// q=s.createQuery("From Resources r").setCacheable(true) // .setCacheRegion("frontpages");// l=q.list();resources=(Resources)l.get(0);System.out.println("-2-"+resources.getName());HibernateSessionFactory.closeSession();} } 本文转自博客园沉睡森林@漂在北京的博客,原文链接:Hibernate+ehcache二级缓存技术,如需转载请自行联系原博主。
服务器端代码: /// <summary> /// Ajax服务器端响应方法 /// </summary> /// <param name="param"></param> /// <returns></returns> [AjaxPro.AjaxMethod] public List<List<string>> GetData(string param) { //获得数据 Hashtable ht = DBHelper.GetDDLHashData(param); List<List<string>> list = new List<List<string>>(); List<string> ilist; //迭代拷贝数据 foreach (DictionaryEntry item in ht) { ilist = new List<string>(); ilist.Add(item.Key.ToString()); ilist.Add(item.Value.ToString()); list.Add(ilist); } return list; } 代码基本上不难,用泛型来包装一个List返回给客户端。再看客户端代码: //添加Dropdownlist内容function AddItemsTosDropdown(array,obj) { try{ var GetObj=document.getElementById(obj); GetObj.length=0; GetObj.options.add(new Option("请选择","")); for(var i=0;i<array.length;i++){ GetObj.options.add(new Option(array[i][1],array[i][0])); } } catch(e){ alert(e.message); } } 调用js方法代码: function selectChangeData(selectedValue) { try { //获得数据并添加到列表框 AddItemsTosDropdown(ItemSeach.GetData(String(selectedValue)).value,"<%=ddlControl.ClientID%>"); }catch(e){ alert(e.message); } } OK!没有一点问题,复制代码只需要改下数据源获取就可以用了,比较通用,但是别忘了AjaxPro使用的基本设置。 大家也可以在这个基础上加强,写得更通用一些:) 本文转自博客园农民伯伯的博客,原文链接:AjaxPro无刷新选择列表框/下拉框[方便|稳定],如需转载请自行联系原博主。
截图 源代码: /Files/over140/ImagesBatchDownloading.rar 欢迎大家多多指教,可以考虑加入多线程和异步获取数据,并且正则表达式有待改善:) 请查看最新版:笨笨图片批量下载器 V0.3 beta[C# | WinForm | 正则表达式 | HttpWebRequest | Async异步编程] new 本文转自博客园农民伯伯的博客,原文链接:笨笨图片批量下载器[C# | WinForm | 正则表达式 | HttpWebRequest],如需转载请自行联系原博主。
先看下我的最终的目录结构(这是工程结构就是利用WebResource.axd通过一个URL来访问装配件的内置资源(译) 英文原站下载的代码): 这里需要说明几点: 1. 对于以下这行资源注册代码放在AssemblyInfo.cs中和放在DLL中任何类的namespace前效果是一样的。(我个人建议统一放在AssemblyInfo.cs中便于统一管理) [assembly: WebResource("FunkyTextBox.Resources.test.jpg", "image/jpeg")] 2. 资源文件在DLL中的位置和访问是有关系的!!我把图上test.jpg放在根目录和放在Resources目录下访问起来是不一样的,注册资源的时候就是根据这个来(也就是说如果放在根目录的话注册资源的名称就是"FunkyTextBox.test.jpg")。 现在我们先分析FunkyTextBox他原来的代码架构,也是很多网上示例的架构: 1. 把资源文件拷贝到项目中 2. 编写自己的用户控件,继承WebControl如TextBox,也就是说在DLL内部调用资源文件 3. 在用户控件中注册资源(也可以在AssemblyInfo.cs中) 基本上看到的都是在DLL内部调用资源文件然后再从外部引用该自定义控件。这里我主要讨论的是想在外部直接引用DLL内部的资源文件,相信很多朋友和我一样,把DLL内部引用资源文件的代码复制出来拷贝到ASPX里面图片怎么都出不来,包括注册httphandles里面截获WebResource.axd也不管用。直到在MSDN上看到那段代码才有所感悟: using System;using System.Web;using System.Web.UI;using System.Security.Permissions; [assembly: WebResource("Samples.AspNet.CS.Controls.script_include.js", "application/x-javascript")]namespace Samples.AspNet.CS.Controls { [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)] public class ClientScriptResourceLabel { // Class code goes here. } } <%@ Page Language="C#"%><%@ Import Namespace="Samples.AspNet.CS.Controls" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><script runat="server"> public void Page_Load(Object sender, EventArgs e) { // Define the resource name and type. String rsname = "Samples.AspNet.CS.Controls.script_include.js"; Type rstype = typeof(ClientScriptResourceLabel); // Get a ClientScriptManager reference from the Page class. ClientScriptManager cs = Page.ClientScript; // Write out the web resource url. ResourcePath.InnerHtml = cs.GetWebResourceUrl(rstype, rsname); // Register the client resource with the page. cs.RegisterClientScriptResource(rstype, rsname); }</script><html > <head> <title>ClientScriptManager Example</title> </head> <body> <form id="Form1" runat="server"> The web resource path is <span id="ResourcePath" runat="server"/>. <br /><br /> <input type="text" id="Message" /> <input type="button" onclick="DoClick()" value="ClientClick" /> </form> </body></html> 为了方便直接看到效果,我把上面从DLL中读取JS的代码改成了从DLL中读取图片的代码,改动如下 1. 将ClientScriptResourceLabel命名空间改为FunkyTextBox 2. 将资源注册代码改成如下(注意资源路径): [assembly: WebResource("FunkyTextBox.Resources.test.jpg", "image/jpeg")] 3. 为ASPX页面添加一个图片按钮并把读取的相应改成如下: <script runat="server"> public void Page_Load(Object sender, EventArgs e) { // Define the resource name and type. String rsname = "FunkyTextBox.Resources.test.jpg"; Type rstype = typeof(ClientScriptResourceLabel); // Get a ClientScriptManager reference from the Page class. ClientScriptManager cs = Page.ClientScript; // Write out the web resource url. imgpath.Src = cs.GetWebResourceUrl(rstype, rsname); //ResourcePath.InnerHtml = // Register the client resource with the page. //cs.RegisterClientScriptResource(rstype, rsname); }</script><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"> <title>WebResources</title></head><body> <form id="form1" runat="server"> <div> <img runat="server" id="imgpath" alt=""/> 上面访问代码可以简化如下: mgpath.Src = ClientScript.GetWebResourceUrl(typeof(FunkyTextBox), "FunkyTextBox.Resources.test.jpg"); 由上面的代码我们可以看得出,ClientScriptResourceLabel类里面是空的,唯一有用的就是注册了一下资源,接下来我们把ClientScriptResourceLabel里面的资源注释掉,把资源注册到AssemblyInfo.cs中,也能够正确显示。这就让我纳闷了!type指向的是一个空的类也能够显示资源,但是我用this.GetType()或用typeof(_Default)通通都不行!!我猜想这个GetWebResourceUrl第一个参数只需要我们把他指引向正确的DLL空间就行了,然后就可以找到资源了!?还有我用Assembly.Load("FunkyTextBox").GetType()来指定Type也是不行的,感觉还是学得比较浅:) 现在基本能达到我的直接访问内部资源文件的要求了,只是需要多一个空类来指定type,暂时满足我的要求,目前可以考虑把JS放到这个里面来,这样一来如果拷贝生成JS的SRC链接直接访问可是不行的哦!就到这里,欢迎多多交流! 补充——代码下载[2008-9-24]: 当时写的Demo,是在别人的源码基础上改的:http://files.cnblogs.com/over140/FunkyTextBox.rar 本文转自博客园农民伯伯的博客,原文链接:C# DLL资源文件打包(图片、JS、CSS)[WebResource],如需转载请自行联系原博主。
一. 先贴一张图,这个界面就是程序的主界面了: 二. 部分代码说明(主要讲解异步分析和下载): 异步分析下载采取的策略是同时分析同时下载,即未等待数据全部分析完毕就开始把已经分析出来的图片链接开始下载。下载成功的均在List框链接前面划上了√ ,未能下载的图片有可能是分析错误或者是下载异常。 1. 异步分析部分代码 /// <summary> /// 异步分析下载 /// </summary> private void AsyncAnalyzeAndDownload(string url, string savePath) { this.uriString = url; this.savePath = savePath; #region 分析计时开始 count = 0; count1 = 0; freq = 0; result = 0; QueryPerformanceFrequency(ref freq); QueryPerformanceCounter(ref count); #endregion using (WebClient wClient = new WebClient()) { AutoResetEvent waiter = new AutoResetEvent(false); wClient.Credentials = CredentialCache.DefaultCredentials; wClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(AsyncURIAnalyze); wClient.DownloadDataAsync(new Uri(uriString), waiter); //waiter.WaitOne(); //阻止当前线程,直到收到信号 } } /// <summary> /// 异步分析 /// </summary> protected void AsyncURIAnalyze(Object sender, DownloadDataCompletedEventArgs e) { AutoResetEvent waiter = (AutoResetEvent)e.UserState; try { if (!e.Cancelled && e.Error == null) { string dnDir = string.Empty; string domainName = string.Empty; string uri = uriString; //获得域名 http://www.sina.com/ Match match = Regex.Match(uri, @"((http(s)?://)?)+[\w-.]+[^/]");//, RegexOptions.IgnoreCase domainName = match.Value; //获得域名最深层目录 http://www.sina.com/mail/ if (domainName.Equals(uri)) dnDir = domainName; else dnDir = uri.Substring(0, uri.LastIndexOf('/')); dnDir += '/'; //获取数据 string pageData = Encoding.UTF8.GetString(e.Result); List<string> urlList = new List<string>(); //匹配全路径 match = Regex.Match(pageData, @"((http(s)?://)?)+(((/?)+[\w-.]+(/))*)+[\w-./]+\.+(" + ImageType + ")"); //, RegexOptions.IgnoreCase while (match.Success) { string item = match.Value; //短路径处理 if (item.IndexOf("http://") == -1 && item.IndexOf("https://") == -1) item = (item[0] == '/' ? domainName : dnDir) + item; if (!urlList.Contains(item)) { urlList.Add(item); imgUrlList.Add(item); //实时显示分析结果 AddlbShowItem(item); //边分析边下载 WebRequest hwr = WebRequest.Create(item); hwr.BeginGetResponse(new AsyncCallback(AsyncDownLoad), hwr); //hwr.Timeout = "0x30D40"; //默认 0x186a0 -> 100000 0x30D40 -> 200000 //hwr.Method = "POST"; //hwr.ContentType = "application/x-www-form-urlencoded"; //hwr.MaximumAutomaticRedirections = 3; //hwr.Accept ="image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"; //hwr.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; //IAsyncResult iar = hwr.BeginGetResponse(new AsyncCallback(AsyncDownLoad), hwr); //iar.AsyncWaitHandle.WaitOne(); } match = match.NextMatch(); } } } finally { waiter.Set(); #region 分析计时结束 QueryPerformanceCounter(ref count1); count = count1 - count; result = (double)(count) / (double)freq; toolStripStatusLabel1.Text = "分析完毕!"; toolStripStatusLabel2.Text = string.Format(" | 分析耗时:{0}秒", result); Application.DoEvents(); #endregion //分析完毕 isAnalyzeComplete = true; } } 这两个方法主要是用WebClient来请求然后异步获得网址所返回的数据并对数据分析,提取图片链接,提取主要有两种方式:一种是完整路径的图片链接;一种是短路径的链接,比如/images/bg.gif,程序会自动为其加上域名部分组成完整的链接。 2. 异步下载部分代码 /// <summary> /// 异步接受数据 /// </summary> /// <param name="asyncResult"></param> public void AsyncDownLoad(IAsyncResult asyncResult) { #region 下载计时开始 if (cfreq == 0) { QueryPerformanceFrequency(ref cfreq); QueryPerformanceCounter(ref ccount); } #endregion WebRequest request = (WebRequest)asyncResult.AsyncState; string url = request.RequestUri.ToString(); try { WebResponse response = request.EndGetResponse(asyncResult); using (Stream stream = response.GetResponseStream()) { Image img = Image.FromStream(stream); string[] tmpUrl = url.Split('.'); img.Save(string.Concat(savePath, "/", DateTime.Now.ToString("yyyyMMddHHmmssfff"), ".", tmpUrl[tmpUrl.Length - 1])); img.Dispose(); stream.Close(); } allDone.Set(); //从未下载的列表中删除已经下载的图片 imgUrlList.Remove(url); //更新列表框 int indexItem = this.lbShow.Items.IndexOf(url); if (indexItem >= 0 && indexItem <= this.lbShow.Items.Count) SetlbShowItem(indexItem); } catch (Exception) { imgUrlList.Remove(url); } } 这部分就是异步下载图片并保存的代码,调用部分请看AsyncURIAnalyze方法分析图片链接匹配成功后就开始进行图片下载,每下载完一张图片就更新显示在界面正下方List框内(在链接前标记√ )。 篇幅有限,还有一起其他重要的代码如 实时显示分析和下载结果 的代码请下载源代码查看。另外需要注意的是输入需要下载图片的网址的时候需要输入完整的链接,带http如http://www.sina.com/ 。 程序和代码: exe可执行文件:http://files.cnblogs.com/over140/IBD_exe.rar 源代码:http://files.cnblogs.com/over140/ImagesBatchDownloading2008-8-21.rar 本文转自博客园农民伯伯的博客,原文链接:笨笨图片批量抓取下载 V0.2 beta[C# | WinForm | 正则表达式 | HttpWebRequest | Async异步编程],如需转载请自行联系原博主。