JBuilder并不支持本地编译机制。但是有一个隐藏的技巧可以让你从可执行文件来启动Java 程序,可以出现或者不出现console窗口。需要JBuilder的bin目录下的这些文件: JBuilder.exe JBuilderW.exe (可选) JBuilder.config。
jdk.config JavaLauncher.dll "JBuilder.exe"是一个通用的可执行外壳文件,用以启动Java程序,"JBuilderW.exe"好像是javaw.exe一样,它把"JBuilder.exe"包装起来运行时候不显示那个conso le的窗口。使用这些文件的关键是文件名。"JBuilder.exe"查找一个文件叫"JBuilder.config"的配置文件,里面包含了运行Java程序的必须信息。
同样的"JBuilderW.exe"查找 "JBuilder.exe"来启动不带Console窗口的Java程序。如果把"JBuilder.exe"重命名为"foo.exe",那"foo.exe"将去寻找"foo.config"配置文件,同样"JBuilderW.exe"被重命名为"fooW.exe",它会去寻找"foo.exe"文件。
如何利用JBuilder.exe来启动应用程序?只要把JBuilder.exe,JBuilerW.exe,JBuilder.config改名成相应的文件名,在JBuilder.config里面指定主类和类路径,就能够通过执行JBuilder.exe(或者被改名后的exe文件)来启动Java应用程序了。
下面是举一例子:
Borland JBuilder 8被安装在E:\jbuilder8\目录下,在E:\jbuilder8\bin\下建立一个temp目录,然后把JBuilder.exe,JBuilder.config,JavaLauncher.dll,jdk.config四个文件拷贝到E:\jbuilder8\bin\temp\目录下,然后在这个目录下建立一个hello目录,在这个目录下生成一个hello.java文件,即E:\jbuilder8\bin\temp\hello\hello.java文件,
//hello.java
package hello;
public class hello{
public static void main(String s[]){
System.out.println("Hello, Exe file!");
}
}
编译java文件,然后打开Jbuilder.config文件,作相应的修改:
在JBuilder.config里面找到下面两行:
# Start JBuilder using the its main class
mainclass com.borland.jbuilder.JBuilder
修改为:
# Start JBuilder using the its main class
mainclass hello.hello
addpath E:/jbuilder5/bin/temp/
addpath命令是把目录加入类路径中,这个命令和其它config里面可以识别的命令可以在JBuilder/bin目录下的config_readme.txt里面找到详细说明。
然后将jdk.config里面的javapath修改成相对的路径,例如原来是:
javapath ../jdk1.4/bin/java
修改成:
javapath ../../jdk1.4/bin/java
最后将JBuilder.exe,JBuilder.config修改成所需要的文件名,例如foo.exe和foo.config文件。
至此,通过修改JBuilder来使用exe文件启动自己的Java应用程序已经完成了但是好玩的地方并不在这个地方,下面的小技巧可能更有趣,将Jar文件打包进入exe文件!
假设利用上面的文件,生成hello.jar包,执行过程:
jar cvf hello.jar hello\*.class
类文件打包成exe文件,然后将jar包附加到JBuilder.exe后面去,执行过程:
copy /b ..\JBuilder.exe+hello.jar foo.exe
将jar文件转化成exe文件
在foo.config(JBuilder.config)文件里面把前面加入的类路径去掉,并加入下面的路径:
addpath E:/jbuilder5/bin/temp/foo.exe
然后执行: foo.exe 将会看到一个含jar包的exe文件被执行了!
这个过程的大致原理是:exe文件的重要信息都在文件头部,所以把乱七八糟的东西放exe文件尾部是不要紧的;而jar/zip文件的重要信息是在文件尾部的,这样它们两不相干,能够容易的被执行。
但是使用这个功能,自己要承担可能带来的风险,因为Borland对这个功能不提供官方的支持!
关于化时钟的题目
这一种是老师讲的方法,就是用三角函数做!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import javax.swing.Timer;
class TimerTest
{
public static void main(String[] args)
{
TimerTestFrame frame = new TimerTestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class TimerTestFrame extends JFrame
{
public TimerTestFrame()
{
setTitle("时钟");
setSize(WIDTH, HEIGHT);
Container c = getContentPane();
c.setLayout(new GridLayout(2, 3));
c.add(new ClockCanvas("America/Los_Angeles"));
c.add(new ClockCanvas("America/New_York"));
c.add(new ClockCanvas("America/Caracas"));
c.add(new ClockCanvas("Europe/Rome"));
c.add(new ClockCanvas("Africa/Cairo"));
c.add(new ClockCanvas("Asia/Shanghai"));
}
public static final int WIDTH = 450;
public static final int HEIGHT = 300;
}
class ClockCanvas extends JPanel
{
public ClockCanvas(String tz)
{
zone = tz;
calendar = new GregorianCalendar(TimeZone.getTimeZone(tz));
Timer t = new Timer(1000, new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
calendar.setTime(new Date());
repaint();
}
});
t.start();
setSize(WIDTH, HEIGHT);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(0, 0, 100, 100);
int seconds = calendar.get(Calendar.HOUR) * 60 * 60+ calendar.get(Calendar.MINUTE) * 60+ calendar.get(Calendar.SECOND);
double hourAngle = 2 * Math.PI* (seconds - 3 * 60 * 60) / (12 * 60 * 60);
double minuteAngle = 2 * Math.PI* (seconds - 15 * 60) / (60 * 60);
double secondAngle = 2 * Math.PI* (seconds - 15) / 60;
g.drawLine(50, 50, 50 + (int)(30* Math.cos(hourAngle)),50 + (int)(30 * Math.sin(hourAngle)));
g.drawLine(50, 50, 50 + (int)(40* Math.cos(minuteAngle)),50 + (int)(40 * Math.sin(minuteAngle)));
g.drawLine(50, 50, 50 + (int)(45* Math.cos(secondAngle)),50 + (int)(45 * Math.sin(secondAngle)));
g.drawString(zone, 0, 115);
}
private String zone;
private GregorianCalendar calendar;
public static final int WIDTH = 125;
public static final int HEIGHT = 125;
}
还有一种是用线程的方法做!
import java.awt.Graphics;
import java.awt.Color;
import java.util.Calendar;
/*类Clock继承了java.applet.Applet,由于要用到线程,因而实现了Runnable接口*/
public class Clock extends java.applet.Applet implements Runnable {
/*声明一个Thread对象threadObj*/
Thread threadObj;
/*下面的6个变量分别代表前一个位置秒针、分针、时针末端的横纵坐标*/
int lastxs, lastys, lastxm,lastym, lastxh, lastyh;
/*lastdate为前一个指针位置对应的日期*/
String lastdate;
/*handColor用于设置时针、分针和钟框的颜色*/
Color handColor;
/*numberColor设置秒针和钟面上数字的颜色*/
Color numberColor;
/*声明一个Calendar对象,用于取得当前时间*/
Calendar rightnow = Calendar.getInstance();
/*获得当前日期的年份并赋给yearInt*/
int yearInt = rightnow.get(rightnow.YEAR);
/*获得当前日期的月份并赋给monthInt*/
int monthInt = rightnow.get(rightnow.MONTH);
/*值得注意的是:月份以0为基准开始计数,一月对应的month值为0,依次类推*/
/*获得当前的日期,赋给dayInt*/
int dayInt = rightnow.get(rightnow.DATE);
/*获得当前时间时钟对应的整数并赋给hoursInt*/
int hoursInt = rightnow.get(rightnow.HOUR_OF_DAY);
/*获得当前时间分针对应的整数并赋给minutesInt*/
int minutesInt = rightnow.get(rightnow.MINUTE);
/*获得当前时间秒针对应的整数并赋给secondsInt*/
int secondsInt = rightnow.get(rightnow.SECOND);
/*获得当前时间对应的星期并赋给dayofweekInt*/
int dayofweekInt = rightnow.get(rightnow.DAY_OF_WEEK);
/*值得注意的是通过DAY_OF_WEEK获得的星期值中,星期天对应的值为1,星期一对应的为2,依次类推,为此,将利用getweekday方法转换(参考getweekday方法)。*/
/*init()方法用来初始化指针的位置和颜色,以及日期*/
public void init() {
/*将秒针、分针和时钟初始位置的横纵坐标设置为0*/
lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0;
/*将上面获得的信息用字符串表示出来*/
lastdate = yearInt + "年" + (monthInt + 1) + "月" + dayInt + "日" + hoursInt + ":" + minutesInt + ":" + secondsInt + " 星期" + getweekday(dayofweekInt);
/*设置时钟上时、分、秒针的颜色*/
handColor = Color.red;
/*设置时钟上数据的颜色*/
numberColor = Color.darkGray;
}
/*下面的方法变换星期的表示,将1,2,3,4,5,7匹配为7,1,2,3,4,5,6*/
public int getweekday(int dayInt) {
int weekdayInt;
switch(dayInt) {
case 1:weekdayInt = 7;
break;
default: weekdayInt = dayInt - 1;
}
return weekdayInt;
}
/*start()方法用来启动Clock线程*/
public void start() {
/*初始化线程对象,名称为"Clock"*/
threadObj = new Thread(this, "Clock");
threadObj.start();
}
/*update()方法用来刷新图象*/
public void update(Graphics g) {
paint(g);
}
/*run()方法用来实现刷新时钟图象*/
public void run() {
while (threadObj != null) {
try {
threadObj.sleep(10);
} catch(InterruptedException e) {}
/*repaint方法用于时间的刷新显示*/
repaint();
}
}
/*paint()绘制指针位置并进行可能的刷新操作,同时显示当前日期和时间*/
public void paint(Graphics g) {
/*下面的前6个int变量分别代表时针、分钟和秒钟外边缘端点的横纵坐标,xcenter和ycenter代表时钟的中心位置*/
int xh, yh, xm, ym, xs, ys, xcenter = 100, ycenter = 70;
/*下面的语句用于获得当前时间*/
Calendar rightnow = Calendar.getInstance();
yearInt = rightnow.get(rightnow.YEAR);
monthInt = rightnow.get(rightnow.MONTH);
dayInt = rightnow.get(rightnow.DATE);
hoursInt = rightnow.get(rightnow.HOUR_OF_DAY);
minutesInt = rightnow.get(rightnow.MINUTE);
secondsInt = rightnow.get(rightnow.SECOND);
dayofweekInt = rightnow.get(rightnow.DAY_OF_WEEK);
/*字符串today包含当前日期和时间信息*/
String today = yearInt + "年" + (monthInt + 1) + "月" + dayInt + "日" + hoursInt + ":" + minutesInt + ":" + secondsInt + " 星期" + getweekday(dayofweekInt);
/*计算秒针、分针、时针外边缘端点的横纵坐标(设定三针长度分别为45,40,30)*/
这里看不懂算法了???
xs = (int)(Math.cos(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + xcenter);
ys = (int)(Math.sin(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + ycenter);
/*值得注意的是,计算分针外边缘端点的横纵坐标时,需要考虑秒针对它的影响*/
xm = (int)(Math.cos((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + xcenter);
ym = (int)(Math.sin((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + ycenter);
/*计算时针外边缘端点的横纵坐标时,需要考虑分针对它的影响,将秒针的影响忽略了*/
xh = (int)(Math.cos((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + xcenter);
yh = (int)(Math.sin((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + ycenter);
/*绘制矩形和数字(9, 12, 3, 6)*/
handColor = Color.red;
g.setColor(handColor);
/*下面的语句绘制红色的矩形外框*/
g.drawRect(xcenter - 50, ycenter - 50, 100, 100);
g.setColor(numberColor);
g.drawString("9",xcenter-45,ycenter+3);
g.drawString("3",xcenter+40,ycenter+3);
g.drawString("12",xcenter-5,ycenter-37);
g.drawString("6",xcenter-3,ycenter+45);
g.setColor(getBackground());
if (xs != lastxs || ys != lastys) {
/*擦除秒针的显示*/
g.drawLine(xcenter, ycenter, lastxs, lastys);
/*擦除界面中日期和时间的字符串*/
g.drawString(lastdate, 30, 150);
}
if (xm != lastxm || ym != lastym) {
/*擦除分针的显示,分针是由两条线组成的*/
g.drawLine(xcenter, ycenter-1, lastxm, lastym);
g.drawLine(xcenter-1, ycenter, lastxm, lastym); }
if (xh != lastxh || yh != lastyh) {
/*擦除时针的显示,也是由两条线组成的*/
g.drawLine(xcenter, ycenter-1, lastxh, lastyh);
g.drawLine(xcenter-1, ycenter, lastxh, lastyh);
}
/*重新显示秒针和时间字符串*/
g.setColor(numberColor);
g.drawString("", 30, 150);
g.drawString(today, 30, 150);
g.drawLine(xcenter, ycenter, xs, ys);
/*将分针和时针的颜色设置为蓝色*/
handColor = Color.blue;
g.setColor(handColor);
/*绘制分针和时针,都分别由两条线组成*/
g.drawLine(xcenter, ycenter - 1, xm, ym);
g.drawLine(xcenter - 1, ycenter, xm, ym);
g.drawLine(xcenter, ycenter - 1, xh, yh);
g.drawLine(xcenter - 1, ycenter, xh, yh);
g.drawLine(xcenter, ycenter - 2, xh, yh);
g.drawLine(xcenter - 2, ycenter, xh, yh);
/*将当前时间的时、分、秒针的横纵坐标赋给前一次时间对应的变量*/
lastxs=xs;
lastys=ys;
lastxm=xm;
lastym=ym;
lastxh=xh;
lastyh=yh;
/*将当前日期赋给上一次日期*/
lastdate = today;
}
}
三角函数部分注解:
表达式中最后加上的xcenter和ycenter是时钟中心的坐标,乘以45、40、30是分别设定秒针、分针、时针的长度。cos()和sin()里的值是每秒钟走过的弧度。
xs = (int)(Math.cos(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + xcenter);
ys = (int)(Math.sin(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + ycenter);
秒针走360度要花60秒,也就是每秒要走6度,每秒走的弧度就是6/180*π即π/30,secondsInt秒的弧度就是secondsInt*π/30,因为水平线是在15秒的位置即0度和0秒的位置相差了15秒,也就是相差了90度即π/2弧度,所以secondsInt秒后的秒针走的角度就是secondsInt*3.14f/30-3.14f/2。
xm = (int)(Math.cos((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + xcenter);
ym = (int)(Math.sin((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + ycenter);
分针每分钟也是走6度,计算方法与秒针同理,因考虑到秒针对它的影响,加上了secondsInt/60分钟,故分针走的弧度为(minutesInt+secondsInt/60f)*3.14f/30-3.14f/2。
xh = (int)(Math.cos((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + xcenter);
yh = (int)(Math.sin((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + ycenter);
时针也是按弧度来算的,每小时时针走360/12=30度,每小时有60分钟,每分钟时针走30/60=0.5度,秒数的影响忽略不计,每小时时针走的弧度是hoursInt*30/180*π+minutesInt*0.5/180*π-π/2即(hoursInt*30+minutesInt/2)*3.14f/180-3.14f/2。
用VB备份和恢复SQL Server数据库的方法
摘要 备份与恢复是数据库管理员维护数据库安全性和完整性的重要操作。本文分析并介绍用Access备份SQL数据库的方法,很好地达到了数据备份的目的。同时,就Access 数据库的安全接口作了简略讨论,使备份后不致丧失数据安全性。并提出了改进备份与恢复策略的一些建议。
关键词 SQL Server数据库; Visual Basic 6.0; 数据备份;数据恢复; Access
引言
对于关键应用的数据库系统应根据具体环境和条件制订一个完善可行确保系统安全的备份计划,没有备份的系统是不可靠、危险的,后果将是严重的,破坏性病毒、误操作、自然灾害等等都可能会对数据库系统造成难以估量的破坏。尤其对一个信息化程度较高的企业来说,最有价值的财产或许就是企业数据库中的数据。一个系统中最重要的是大量的实时数据,没有备份功能显然是不安全和不完善的。经过实践摸索出Visual Basic 6.0开发的备份程序,能将数据库备份到Access数据库(Access 为目前流行的桌面型数据库产品, 具有存储操作灵活、便利等优点, 并且因它与SQL Server 同属微软数据库产品, 二者能很好地兼容)中,并对Access数据库进行加密以防数据被非法访问。该程序还能用Access备份库的数据恢复SQL Server数据库,从而减少因误操作损坏数据内容而造成的损失。使用该方法,用户不须添加额外设备,只须在原有服务器上运行该备份程序,其界面简单方便,适合普通用户使用。
备份与恢复概述
备份是数据库管理员定期地将整个数据库复制到磁带或另一个磁盘上保存起来的过程。常用的数据备份类型有:完全备份、差异备份、事务日志备份、文件或文件组备份。一个通用的备份策略是:以较长的时间间隔执行完全备份,以适中的时间间隔进行差异备份,并以较短的时间间隔进行事务日志备份。当数据遭到破坏后就可以利用备份来恢复数据库。恢复数据库是一个装载数据库的备份,然后应用事务日志重建的过程。一个通用的恢复策略是:首先恢复完全备份的数据,然后恢复差异备份数据,最后根据事务日志备份进行恢复。
1、备份方案
开发所需软件:Visual Basic 6.0 Access备份程序的设计方法:
(1) 用控制面版的ODBC设置,给SQL Server中的数据库添加一个数据源名称。
(2) 在Access中新建一个数据库,命名为backup.mdb。
(3) 用VB定义两个主要过程:Attach_Table()和Create_Table()。Attach_Table的作用是将SQL Server数据库中的所有需要备份的表链接到Access数据库中,在此过程中要排除系统表,因为那是SQL Server自创建的,表中无用户数据。Create_Table的作用是在backup.mdb中创建目的表,即在这个备份Access库中创建表用来保存所有存在SQL数据库中的用户数据。另外,在链接过程中,要去掉SQL Server自带的拥有者名称。
2、程序的逻辑结构
① 通过第一步创建的ODBC数据源打开要备份的SQL数据库;
② 使用Attach_Table()将该数据库中的所有用户表链接到backup.mdb中,排除系统表的方法是:
For Each tdf in backup_db.TableDefs
If (tdf.attributes And dbSystemObject)=0 Then
//条件成立,说明该表是用户定义的表,可以链接,否则跳过
End if
Next
③ 使用Create_Table()对每个表创建与之对应的备份表,取名可遵循如下原则, 若原表叫table_name, 则备份表叫b_table_name。
④ 将table_name表中的所有记录复制到b_table_name中。
⑤从备份库删除对SQL数据表的链接。
3、程序原码
采用微软DAO (Data Access Object) 数据模型, 打开Access 本地数据库, 并连接一个外部ODBC数据表, 拷贝该表结构完成, 有以下过程块CopyStru :
Private Sub copyStru ()
Set dbsTemp = wrkjet. OpenDatabase (tagFilName)// 链接表的过程
For i = 0 To tabN - 1
Set tdfLinked = dbsTemp. CreateTableDef ("linkTab")
tdfLinked. Connect = "OdbC; DATABASE = xgsbgsys ; UID =
sa ; PWD = ; DSN = xgsdb ;"
tdfLinked. SourceTableName = tabName (i)
dbsTemp. TableDefs. Append tdfLinked
Set temp Tab = dbsTemp. CreateTableDef ()
temp Tab. Name = tabName (i)
//创建新表的过程
For Each fld In tdfLinked. Fields
Set newFil = temp Tab. CreateField (fld. Name , fld. Type ,fld. Size)
newFil. OrdinalPosition = fld. OrdinalPosition
newFil. Required = fld. Required
temp Tab. Fields. Append newFil
Next
//创建索引
For Each idx In tdfLinked. Indexes
Set newIdx = temp Tab. CreateIndex ()
With newIdx
Name = tabName (i) & " x"
Fields = idx. Fields
Unique = idx. Unique
Primary = idx. Primary
End With
temp Tab. Indexes. Append newIdx
Next
dbsTemp. TableDefs. Append temp Tab
Set temp Tab = Nothing
dbsTemp. TableDefs. Delete "linkTab"
Next i
dbsTemp. Close
Set dbsTemp = Nothing
wrkjet. Close
Set wrkjet = Nothing
End Sub
End Sub
追加数据, 采用微软ADO (ActiveX data object) 数据模型, 分别操纵SQL Server 和Access 数据对象, 追加记录数据来完成, 有以下过程块CopyDa2ta :
Private Sub copyData ()
Set sourceCn = New adodb. Connection
sourceCn. CursorLocation = adUseServer
strSql ="PROVIDER = MSDASQL ; dsn = xgsdb ; uid = sa ;
pwd = ;"
sourceCn. Open strSql
Set targetCn = New adodb. Connection
targetCn. CursorLocation = adUseClient
targetCn. Open " PROVIDER = Microsoft. Jet. OL Edb. 3.51 ;
Data Source = "& tagFilName &";"
End If //追加新表
For i = 0 To tabN - 1
Set targetRst = New adodb. Recordset
strSql = "select 3 from "& tabName (i)
targetRst. Open strSql , targetCn , adOpenStatic , adLockPes2simistic , adCmdText
Set sourceSet = New adodb. Recordset
strSql = "select 3 from "& tabName (i) & strSQLApp
sourceSet. Open strSql , sourceCn
zdN = sourceSet. Fields. Count
If sourceSet. EOF Then Go To hh
sourceSet. MoveFirst
Do While Not sourceSet. EOF
targetRst. AddNew
For j = 0 To zdN - 1
If Trim (sourceSet. Fields (j) . value) = ""Then
targetRst. Fields (j) . value = Null
Else
targetRst. Fields (j) . value = Trim (sourceSet. Fields(j) . value)
End If //复制记录
Next
targetRst. Update
sourceSet. MoveNext
Loop
recN = targetRst. RecordCount
hh :sourceSet. Close
Set sourceSet = Nothing
targetRst. Close
Set targetRst = Nothing
Next
targetCn. Close
Set targetCn = Nothing
sourceCn. Close
Set sourceCn = Nothing
End Sub //删除链接
其中字符数组tabName (i) 中存放需备份的各数据表名, strSQLAPP 字符串中存放对数据表的限制条件where 子句内容。
4、数据恢复
如果要从Access中将数据恢复到SQL Server中,方法类似,仅仅是拷贝记录的方向和以上相反,即从Access表往链接过来的SQL表中拷贝。
安全方案
因为Access属小型数据库,所以要保证其不被非法访问。可以在VB程序中实现对备份数据库的安全性接口,有以下两种方法限制对Access的任意访问:
(1)给Access数据库加口令,在VB程序中用口令打开数据库。打开Access软件,选中"工具"菜单,选择"安全"项,选择"加密/解密数据库",然后选择备份数据库的名字,就可以给这个数据库加上密码。这样的话,任何人如果想打开备份数据库,手动修改数据表内容,必须先输入正确的访问密码,否则不能继续操作。用VB程序打开数据库时,必须提供访问密码,否则无法访问数据库。
(2)给Access数据库定义不同的用户组和用户权限,从而使不同级别的用户可以分别读或写某表或视图。打开Access软件,选中"工具"菜单,选择"安全"项,选择"用户/组权限",在此可定义不同的组和用户,并按组划分用户的权限级别,从而限制低或无权限的用户执行某些操作。用VB 程序打开数据库进行操作时,对不同的操作采用不同的用户名和用户密码,从而区分有不同使用权限的人的访问操作。
备份方案的几点建议
1、在业余时间执行完全备份
如果你的公司没有工作在24时的环境之下,那么业余时间是执行备份的最佳时间。这既可以提高备份的性能,又可以减少备份对用户的影响。
2、安排一个完全备份在几天内完成
如果数据库非常大,并且你不能在期限内完成一个完全备份,那么就把该备份进行分解。你可以在一部分数据库中执行文件或文件组备份。照这样,经过几天,就可以备份所有的数据。
3、使用差异备份
如果你没有时间每天晚上执行一个完全备份,那么就可以在一周之中执行差异备份,而在周末执行一个完全备份。
4、建立一张合理的备份时间表
一个提高正被备份的系统性能的最好办法是不要做不必要的备份。必须根据要求确定最有效的备份时间表。不要做超过你所需要的备份,但是也不要因为性能而牺牲数据的安全。根据你的要求,建立对自己最有利的备份计划。
结束语
该备份方案使用VB设计出友好方便的用户界面,用户只需点击按钮便可执行备份或恢复操作;而且用Access作备份数据库,备份同样的数据,其所占用的硬盘空间远远小于SQL数据库所占空间,大大地提高了效率和节约了用户资源。通过实践检验,其运行效率比双机备份要高得多。
jdk.config JavaLauncher.dll "JBuilder.exe"是一个通用的可执行外壳文件,用以启动Java程序,"JBuilderW.exe"好像是javaw.exe一样,它把"JBuilder.exe"包装起来运行时候不显示那个conso le的窗口。使用这些文件的关键是文件名。"JBuilder.exe"查找一个文件叫"JBuilder.config"的配置文件,里面包含了运行Java程序的必须信息。
同样的"JBuilderW.exe"查找 "JBuilder.exe"来启动不带Console窗口的Java程序。如果把"JBuilder.exe"重命名为"foo.exe",那"foo.exe"将去寻找"foo.config"配置文件,同样"JBuilderW.exe"被重命名为"fooW.exe",它会去寻找"foo.exe"文件。
如何利用JBuilder.exe来启动应用程序?只要把JBuilder.exe,JBuilerW.exe,JBuilder.config改名成相应的文件名,在JBuilder.config里面指定主类和类路径,就能够通过执行JBuilder.exe(或者被改名后的exe文件)来启动Java应用程序了。
下面是举一例子:
Borland JBuilder 8被安装在E:\jbuilder8\目录下,在E:\jbuilder8\bin\下建立一个temp目录,然后把JBuilder.exe,JBuilder.config,JavaLauncher.dll,jdk.config四个文件拷贝到E:\jbuilder8\bin\temp\目录下,然后在这个目录下建立一个hello目录,在这个目录下生成一个hello.java文件,即E:\jbuilder8\bin\temp\hello\hello.java文件,
//hello.java
package hello;
public class hello{
public static void main(String s[]){
System.out.println("Hello, Exe file!");
}
}
编译java文件,然后打开Jbuilder.config文件,作相应的修改:
在JBuilder.config里面找到下面两行:
# Start JBuilder using the its main class
mainclass com.borland.jbuilder.JBuilder
修改为:
# Start JBuilder using the its main class
mainclass hello.hello
addpath E:/jbuilder5/bin/temp/
addpath命令是把目录加入类路径中,这个命令和其它config里面可以识别的命令可以在JBuilder/bin目录下的config_readme.txt里面找到详细说明。
然后将jdk.config里面的javapath修改成相对的路径,例如原来是:
javapath ../jdk1.4/bin/java
修改成:
javapath ../../jdk1.4/bin/java
最后将JBuilder.exe,JBuilder.config修改成所需要的文件名,例如foo.exe和foo.config文件。
至此,通过修改JBuilder来使用exe文件启动自己的Java应用程序已经完成了但是好玩的地方并不在这个地方,下面的小技巧可能更有趣,将Jar文件打包进入exe文件!
假设利用上面的文件,生成hello.jar包,执行过程:
jar cvf hello.jar hello\*.class
类文件打包成exe文件,然后将jar包附加到JBuilder.exe后面去,执行过程:
copy /b ..\JBuilder.exe+hello.jar foo.exe
将jar文件转化成exe文件
在foo.config(JBuilder.config)文件里面把前面加入的类路径去掉,并加入下面的路径:
addpath E:/jbuilder5/bin/temp/foo.exe
然后执行: foo.exe 将会看到一个含jar包的exe文件被执行了!
这个过程的大致原理是:exe文件的重要信息都在文件头部,所以把乱七八糟的东西放exe文件尾部是不要紧的;而jar/zip文件的重要信息是在文件尾部的,这样它们两不相干,能够容易的被执行。
但是使用这个功能,自己要承担可能带来的风险,因为Borland对这个功能不提供官方的支持!
关于化时钟的题目
这一种是老师讲的方法,就是用三角函数做!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import javax.swing.Timer;
class TimerTest
{
public static void main(String[] args)
{
TimerTestFrame frame = new TimerTestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class TimerTestFrame extends JFrame
{
public TimerTestFrame()
{
setTitle("时钟");
setSize(WIDTH, HEIGHT);
Container c = getContentPane();
c.setLayout(new GridLayout(2, 3));
c.add(new ClockCanvas("America/Los_Angeles"));
c.add(new ClockCanvas("America/New_York"));
c.add(new ClockCanvas("America/Caracas"));
c.add(new ClockCanvas("Europe/Rome"));
c.add(new ClockCanvas("Africa/Cairo"));
c.add(new ClockCanvas("Asia/Shanghai"));
}
public static final int WIDTH = 450;
public static final int HEIGHT = 300;
}
class ClockCanvas extends JPanel
{
public ClockCanvas(String tz)
{
zone = tz;
calendar = new GregorianCalendar(TimeZone.getTimeZone(tz));
Timer t = new Timer(1000, new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
calendar.setTime(new Date());
repaint();
}
});
t.start();
setSize(WIDTH, HEIGHT);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(0, 0, 100, 100);
int seconds = calendar.get(Calendar.HOUR) * 60 * 60+ calendar.get(Calendar.MINUTE) * 60+ calendar.get(Calendar.SECOND);
double hourAngle = 2 * Math.PI* (seconds - 3 * 60 * 60) / (12 * 60 * 60);
double minuteAngle = 2 * Math.PI* (seconds - 15 * 60) / (60 * 60);
double secondAngle = 2 * Math.PI* (seconds - 15) / 60;
g.drawLine(50, 50, 50 + (int)(30* Math.cos(hourAngle)),50 + (int)(30 * Math.sin(hourAngle)));
g.drawLine(50, 50, 50 + (int)(40* Math.cos(minuteAngle)),50 + (int)(40 * Math.sin(minuteAngle)));
g.drawLine(50, 50, 50 + (int)(45* Math.cos(secondAngle)),50 + (int)(45 * Math.sin(secondAngle)));
g.drawString(zone, 0, 115);
}
private String zone;
private GregorianCalendar calendar;
public static final int WIDTH = 125;
public static final int HEIGHT = 125;
}
还有一种是用线程的方法做!
import java.awt.Graphics;
import java.awt.Color;
import java.util.Calendar;
/*类Clock继承了java.applet.Applet,由于要用到线程,因而实现了Runnable接口*/
public class Clock extends java.applet.Applet implements Runnable {
/*声明一个Thread对象threadObj*/
Thread threadObj;
/*下面的6个变量分别代表前一个位置秒针、分针、时针末端的横纵坐标*/
int lastxs, lastys, lastxm,lastym, lastxh, lastyh;
/*lastdate为前一个指针位置对应的日期*/
String lastdate;
/*handColor用于设置时针、分针和钟框的颜色*/
Color handColor;
/*numberColor设置秒针和钟面上数字的颜色*/
Color numberColor;
/*声明一个Calendar对象,用于取得当前时间*/
Calendar rightnow = Calendar.getInstance();
/*获得当前日期的年份并赋给yearInt*/
int yearInt = rightnow.get(rightnow.YEAR);
/*获得当前日期的月份并赋给monthInt*/
int monthInt = rightnow.get(rightnow.MONTH);
/*值得注意的是:月份以0为基准开始计数,一月对应的month值为0,依次类推*/
/*获得当前的日期,赋给dayInt*/
int dayInt = rightnow.get(rightnow.DATE);
/*获得当前时间时钟对应的整数并赋给hoursInt*/
int hoursInt = rightnow.get(rightnow.HOUR_OF_DAY);
/*获得当前时间分针对应的整数并赋给minutesInt*/
int minutesInt = rightnow.get(rightnow.MINUTE);
/*获得当前时间秒针对应的整数并赋给secondsInt*/
int secondsInt = rightnow.get(rightnow.SECOND);
/*获得当前时间对应的星期并赋给dayofweekInt*/
int dayofweekInt = rightnow.get(rightnow.DAY_OF_WEEK);
/*值得注意的是通过DAY_OF_WEEK获得的星期值中,星期天对应的值为1,星期一对应的为2,依次类推,为此,将利用getweekday方法转换(参考getweekday方法)。*/
/*init()方法用来初始化指针的位置和颜色,以及日期*/
public void init() {
/*将秒针、分针和时钟初始位置的横纵坐标设置为0*/
lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0;
/*将上面获得的信息用字符串表示出来*/
lastdate = yearInt + "年" + (monthInt + 1) + "月" + dayInt + "日" + hoursInt + ":" + minutesInt + ":" + secondsInt + " 星期" + getweekday(dayofweekInt);
/*设置时钟上时、分、秒针的颜色*/
handColor = Color.red;
/*设置时钟上数据的颜色*/
numberColor = Color.darkGray;
}
/*下面的方法变换星期的表示,将1,2,3,4,5,7匹配为7,1,2,3,4,5,6*/
public int getweekday(int dayInt) {
int weekdayInt;
switch(dayInt) {
case 1:weekdayInt = 7;
break;
default: weekdayInt = dayInt - 1;
}
return weekdayInt;
}
/*start()方法用来启动Clock线程*/
public void start() {
/*初始化线程对象,名称为"Clock"*/
threadObj = new Thread(this, "Clock");
threadObj.start();
}
/*update()方法用来刷新图象*/
public void update(Graphics g) {
paint(g);
}
/*run()方法用来实现刷新时钟图象*/
public void run() {
while (threadObj != null) {
try {
threadObj.sleep(10);
} catch(InterruptedException e) {}
/*repaint方法用于时间的刷新显示*/
repaint();
}
}
/*paint()绘制指针位置并进行可能的刷新操作,同时显示当前日期和时间*/
public void paint(Graphics g) {
/*下面的前6个int变量分别代表时针、分钟和秒钟外边缘端点的横纵坐标,xcenter和ycenter代表时钟的中心位置*/
int xh, yh, xm, ym, xs, ys, xcenter = 100, ycenter = 70;
/*下面的语句用于获得当前时间*/
Calendar rightnow = Calendar.getInstance();
yearInt = rightnow.get(rightnow.YEAR);
monthInt = rightnow.get(rightnow.MONTH);
dayInt = rightnow.get(rightnow.DATE);
hoursInt = rightnow.get(rightnow.HOUR_OF_DAY);
minutesInt = rightnow.get(rightnow.MINUTE);
secondsInt = rightnow.get(rightnow.SECOND);
dayofweekInt = rightnow.get(rightnow.DAY_OF_WEEK);
/*字符串today包含当前日期和时间信息*/
String today = yearInt + "年" + (monthInt + 1) + "月" + dayInt + "日" + hoursInt + ":" + minutesInt + ":" + secondsInt + " 星期" + getweekday(dayofweekInt);
/*计算秒针、分针、时针外边缘端点的横纵坐标(设定三针长度分别为45,40,30)*/
这里看不懂算法了???
xs = (int)(Math.cos(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + xcenter);
ys = (int)(Math.sin(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + ycenter);
/*值得注意的是,计算分针外边缘端点的横纵坐标时,需要考虑秒针对它的影响*/
xm = (int)(Math.cos((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + xcenter);
ym = (int)(Math.sin((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + ycenter);
/*计算时针外边缘端点的横纵坐标时,需要考虑分针对它的影响,将秒针的影响忽略了*/
xh = (int)(Math.cos((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + xcenter);
yh = (int)(Math.sin((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + ycenter);
/*绘制矩形和数字(9, 12, 3, 6)*/
handColor = Color.red;
g.setColor(handColor);
/*下面的语句绘制红色的矩形外框*/
g.drawRect(xcenter - 50, ycenter - 50, 100, 100);
g.setColor(numberColor);
g.drawString("9",xcenter-45,ycenter+3);
g.drawString("3",xcenter+40,ycenter+3);
g.drawString("12",xcenter-5,ycenter-37);
g.drawString("6",xcenter-3,ycenter+45);
g.setColor(getBackground());
if (xs != lastxs || ys != lastys) {
/*擦除秒针的显示*/
g.drawLine(xcenter, ycenter, lastxs, lastys);
/*擦除界面中日期和时间的字符串*/
g.drawString(lastdate, 30, 150);
}
if (xm != lastxm || ym != lastym) {
/*擦除分针的显示,分针是由两条线组成的*/
g.drawLine(xcenter, ycenter-1, lastxm, lastym);
g.drawLine(xcenter-1, ycenter, lastxm, lastym); }
if (xh != lastxh || yh != lastyh) {
/*擦除时针的显示,也是由两条线组成的*/
g.drawLine(xcenter, ycenter-1, lastxh, lastyh);
g.drawLine(xcenter-1, ycenter, lastxh, lastyh);
}
/*重新显示秒针和时间字符串*/
g.setColor(numberColor);
g.drawString("", 30, 150);
g.drawString(today, 30, 150);
g.drawLine(xcenter, ycenter, xs, ys);
/*将分针和时针的颜色设置为蓝色*/
handColor = Color.blue;
g.setColor(handColor);
/*绘制分针和时针,都分别由两条线组成*/
g.drawLine(xcenter, ycenter - 1, xm, ym);
g.drawLine(xcenter - 1, ycenter, xm, ym);
g.drawLine(xcenter, ycenter - 1, xh, yh);
g.drawLine(xcenter - 1, ycenter, xh, yh);
g.drawLine(xcenter, ycenter - 2, xh, yh);
g.drawLine(xcenter - 2, ycenter, xh, yh);
/*将当前时间的时、分、秒针的横纵坐标赋给前一次时间对应的变量*/
lastxs=xs;
lastys=ys;
lastxm=xm;
lastym=ym;
lastxh=xh;
lastyh=yh;
/*将当前日期赋给上一次日期*/
lastdate = today;
}
}
三角函数部分注解:
表达式中最后加上的xcenter和ycenter是时钟中心的坐标,乘以45、40、30是分别设定秒针、分针、时针的长度。cos()和sin()里的值是每秒钟走过的弧度。
xs = (int)(Math.cos(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + xcenter);
ys = (int)(Math.sin(secondsInt * 3.14f / 30 - 3.14f / 2) * 45 + ycenter);
秒针走360度要花60秒,也就是每秒要走6度,每秒走的弧度就是6/180*π即π/30,secondsInt秒的弧度就是secondsInt*π/30,因为水平线是在15秒的位置即0度和0秒的位置相差了15秒,也就是相差了90度即π/2弧度,所以secondsInt秒后的秒针走的角度就是secondsInt*3.14f/30-3.14f/2。
xm = (int)(Math.cos((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + xcenter);
ym = (int)(Math.sin((minutesInt + secondsInt/60f) * 3.14f / 30 - 3.14f / 2) * 40 + ycenter);
分针每分钟也是走6度,计算方法与秒针同理,因考虑到秒针对它的影响,加上了secondsInt/60分钟,故分针走的弧度为(minutesInt+secondsInt/60f)*3.14f/30-3.14f/2。
xh = (int)(Math.cos((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + xcenter);
yh = (int)(Math.sin((hoursInt * 30 + minutesInt / 2) * 3.14f / 180 - 3.14f/2) * 30 + ycenter);
时针也是按弧度来算的,每小时时针走360/12=30度,每小时有60分钟,每分钟时针走30/60=0.5度,秒数的影响忽略不计,每小时时针走的弧度是hoursInt*30/180*π+minutesInt*0.5/180*π-π/2即(hoursInt*30+minutesInt/2)*3.14f/180-3.14f/2。
用VB备份和恢复SQL Server数据库的方法
摘要 备份与恢复是数据库管理员维护数据库安全性和完整性的重要操作。本文分析并介绍用Access备份SQL数据库的方法,很好地达到了数据备份的目的。同时,就Access 数据库的安全接口作了简略讨论,使备份后不致丧失数据安全性。并提出了改进备份与恢复策略的一些建议。
关键词 SQL Server数据库; Visual Basic 6.0; 数据备份;数据恢复; Access
引言
对于关键应用的数据库系统应根据具体环境和条件制订一个完善可行确保系统安全的备份计划,没有备份的系统是不可靠、危险的,后果将是严重的,破坏性病毒、误操作、自然灾害等等都可能会对数据库系统造成难以估量的破坏。尤其对一个信息化程度较高的企业来说,最有价值的财产或许就是企业数据库中的数据。一个系统中最重要的是大量的实时数据,没有备份功能显然是不安全和不完善的。经过实践摸索出Visual Basic 6.0开发的备份程序,能将数据库备份到Access数据库(Access 为目前流行的桌面型数据库产品, 具有存储操作灵活、便利等优点, 并且因它与SQL Server 同属微软数据库产品, 二者能很好地兼容)中,并对Access数据库进行加密以防数据被非法访问。该程序还能用Access备份库的数据恢复SQL Server数据库,从而减少因误操作损坏数据内容而造成的损失。使用该方法,用户不须添加额外设备,只须在原有服务器上运行该备份程序,其界面简单方便,适合普通用户使用。
备份与恢复概述
备份是数据库管理员定期地将整个数据库复制到磁带或另一个磁盘上保存起来的过程。常用的数据备份类型有:完全备份、差异备份、事务日志备份、文件或文件组备份。一个通用的备份策略是:以较长的时间间隔执行完全备份,以适中的时间间隔进行差异备份,并以较短的时间间隔进行事务日志备份。当数据遭到破坏后就可以利用备份来恢复数据库。恢复数据库是一个装载数据库的备份,然后应用事务日志重建的过程。一个通用的恢复策略是:首先恢复完全备份的数据,然后恢复差异备份数据,最后根据事务日志备份进行恢复。
1、备份方案
开发所需软件:Visual Basic 6.0 Access备份程序的设计方法:
(1) 用控制面版的ODBC设置,给SQL Server中的数据库添加一个数据源名称。
(2) 在Access中新建一个数据库,命名为backup.mdb。
(3) 用VB定义两个主要过程:Attach_Table()和Create_Table()。Attach_Table的作用是将SQL Server数据库中的所有需要备份的表链接到Access数据库中,在此过程中要排除系统表,因为那是SQL Server自创建的,表中无用户数据。Create_Table的作用是在backup.mdb中创建目的表,即在这个备份Access库中创建表用来保存所有存在SQL数据库中的用户数据。另外,在链接过程中,要去掉SQL Server自带的拥有者名称。
2、程序的逻辑结构
① 通过第一步创建的ODBC数据源打开要备份的SQL数据库;
② 使用Attach_Table()将该数据库中的所有用户表链接到backup.mdb中,排除系统表的方法是:
For Each tdf in backup_db.TableDefs
If (tdf.attributes And dbSystemObject)=0 Then
//条件成立,说明该表是用户定义的表,可以链接,否则跳过
End if
Next
③ 使用Create_Table()对每个表创建与之对应的备份表,取名可遵循如下原则, 若原表叫table_name, 则备份表叫b_table_name。
④ 将table_name表中的所有记录复制到b_table_name中。
⑤从备份库删除对SQL数据表的链接。
3、程序原码
采用微软DAO (Data Access Object) 数据模型, 打开Access 本地数据库, 并连接一个外部ODBC数据表, 拷贝该表结构完成, 有以下过程块CopyStru :
Private Sub copyStru ()
Set dbsTemp = wrkjet. OpenDatabase (tagFilName)// 链接表的过程
For i = 0 To tabN - 1
Set tdfLinked = dbsTemp. CreateTableDef ("linkTab")
tdfLinked. Connect = "OdbC; DATABASE = xgsbgsys ; UID =
sa ; PWD = ; DSN = xgsdb ;"
tdfLinked. SourceTableName = tabName (i)
dbsTemp. TableDefs. Append tdfLinked
Set temp Tab = dbsTemp. CreateTableDef ()
temp Tab. Name = tabName (i)
//创建新表的过程
For Each fld In tdfLinked. Fields
Set newFil = temp Tab. CreateField (fld. Name , fld. Type ,fld. Size)
newFil. OrdinalPosition = fld. OrdinalPosition
newFil. Required = fld. Required
temp Tab. Fields. Append newFil
Next
//创建索引
For Each idx In tdfLinked. Indexes
Set newIdx = temp Tab. CreateIndex ()
With newIdx
Name = tabName (i) & " x"
Fields = idx. Fields
Unique = idx. Unique
Primary = idx. Primary
End With
temp Tab. Indexes. Append newIdx
Next
dbsTemp. TableDefs. Append temp Tab
Set temp Tab = Nothing
dbsTemp. TableDefs. Delete "linkTab"
Next i
dbsTemp. Close
Set dbsTemp = Nothing
wrkjet. Close
Set wrkjet = Nothing
End Sub
End Sub
追加数据, 采用微软ADO (ActiveX data object) 数据模型, 分别操纵SQL Server 和Access 数据对象, 追加记录数据来完成, 有以下过程块CopyDa2ta :
Private Sub copyData ()
Set sourceCn = New adodb. Connection
sourceCn. CursorLocation = adUseServer
strSql ="PROVIDER = MSDASQL ; dsn = xgsdb ; uid = sa ;
pwd = ;"
sourceCn. Open strSql
Set targetCn = New adodb. Connection
targetCn. CursorLocation = adUseClient
targetCn. Open " PROVIDER = Microsoft. Jet. OL Edb. 3.51 ;
Data Source = "& tagFilName &";"
End If //追加新表
For i = 0 To tabN - 1
Set targetRst = New adodb. Recordset
strSql = "select 3 from "& tabName (i)
targetRst. Open strSql , targetCn , adOpenStatic , adLockPes2simistic , adCmdText
Set sourceSet = New adodb. Recordset
strSql = "select 3 from "& tabName (i) & strSQLApp
sourceSet. Open strSql , sourceCn
zdN = sourceSet. Fields. Count
If sourceSet. EOF Then Go To hh
sourceSet. MoveFirst
Do While Not sourceSet. EOF
targetRst. AddNew
For j = 0 To zdN - 1
If Trim (sourceSet. Fields (j) . value) = ""Then
targetRst. Fields (j) . value = Null
Else
targetRst. Fields (j) . value = Trim (sourceSet. Fields(j) . value)
End If //复制记录
Next
targetRst. Update
sourceSet. MoveNext
Loop
recN = targetRst. RecordCount
hh :sourceSet. Close
Set sourceSet = Nothing
targetRst. Close
Set targetRst = Nothing
Next
targetCn. Close
Set targetCn = Nothing
sourceCn. Close
Set sourceCn = Nothing
End Sub //删除链接
其中字符数组tabName (i) 中存放需备份的各数据表名, strSQLAPP 字符串中存放对数据表的限制条件where 子句内容。
4、数据恢复
如果要从Access中将数据恢复到SQL Server中,方法类似,仅仅是拷贝记录的方向和以上相反,即从Access表往链接过来的SQL表中拷贝。
安全方案
因为Access属小型数据库,所以要保证其不被非法访问。可以在VB程序中实现对备份数据库的安全性接口,有以下两种方法限制对Access的任意访问:
(1)给Access数据库加口令,在VB程序中用口令打开数据库。打开Access软件,选中"工具"菜单,选择"安全"项,选择"加密/解密数据库",然后选择备份数据库的名字,就可以给这个数据库加上密码。这样的话,任何人如果想打开备份数据库,手动修改数据表内容,必须先输入正确的访问密码,否则不能继续操作。用VB程序打开数据库时,必须提供访问密码,否则无法访问数据库。
(2)给Access数据库定义不同的用户组和用户权限,从而使不同级别的用户可以分别读或写某表或视图。打开Access软件,选中"工具"菜单,选择"安全"项,选择"用户/组权限",在此可定义不同的组和用户,并按组划分用户的权限级别,从而限制低或无权限的用户执行某些操作。用VB 程序打开数据库进行操作时,对不同的操作采用不同的用户名和用户密码,从而区分有不同使用权限的人的访问操作。
备份方案的几点建议
1、在业余时间执行完全备份
如果你的公司没有工作在24时的环境之下,那么业余时间是执行备份的最佳时间。这既可以提高备份的性能,又可以减少备份对用户的影响。
2、安排一个完全备份在几天内完成
如果数据库非常大,并且你不能在期限内完成一个完全备份,那么就把该备份进行分解。你可以在一部分数据库中执行文件或文件组备份。照这样,经过几天,就可以备份所有的数据。
3、使用差异备份
如果你没有时间每天晚上执行一个完全备份,那么就可以在一周之中执行差异备份,而在周末执行一个完全备份。
4、建立一张合理的备份时间表
一个提高正被备份的系统性能的最好办法是不要做不必要的备份。必须根据要求确定最有效的备份时间表。不要做超过你所需要的备份,但是也不要因为性能而牺牲数据的安全。根据你的要求,建立对自己最有利的备份计划。
结束语
该备份方案使用VB设计出友好方便的用户界面,用户只需点击按钮便可执行备份或恢复操作;而且用Access作备份数据库,备份同样的数据,其所占用的硬盘空间远远小于SQL数据库所占空间,大大地提高了效率和节约了用户资源。通过实践检验,其运行效率比双机备份要高得多。
回复Comments
{commenttime}{commentauthor}
{CommentUrl}
{commentcontent}