怎么实现2同时更新多个数据库库同时使用?

BroadcastReceiver 是android四大组件的一个,本质上是一种全局的监听器,用于监听全局的广播消息。下面实现了后台监听android手机通话记录。本demo分两个程序,第一个程序是设置监听器,然后模拟器重启后就会有一个全局的service在后台监听你的来电显示,大多数通话管理软件都是这么干的,第二个项目是获取通话记录的,由于只是做一个小实验,所以是根据某个项目改的,里面涉及到一些ContentPrivler的知识,还有sqllite数据库,里面定义名称并非其意思。
第一个程序代码配置文件
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="com.android"
android:versionCode="1"
android:versionName="1.0" &
&application android:icon="@drawable/ic_launcher" android:label="@string/app_name"&
&service android:name=".TtActivity"&
&/service&
&!-- 定义一个BroadcastReceiver,监听系统开机广播
&receiver android:name=".LaunchReceiver"&
&intent-filter&
&action android:name="android.intent.action.BOOT_COMPLETED" /&
&/intent-filter&
&/receiver&
&provider android:name=".DictProvider"
android:authorities="org.crazyit.providers.dictprovider"/&
&/application&
&!-- 授予应用程序访问系统开机事件的权限 --&
&uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/&
&/manifest&
package com.
import android.content.BroadcastR
import android.content.C
import android.content.I
public class LaunchReceiver extends BroadcastReceiver
public void onReceive(Context context, Intent intent)
Intent tIntent = new Intent(context , TtActivity.class);
// 启动指定Service
context.startService(tIntent);
package com.
import android.content.C
import android.database.sqlite.SQLiteD
import android.database.sqlite.SQLiteOpenH
public class MyDatabaseHelper extends SQLiteOpenHelper
final String CREATE_TABLE_SQL =
"create table dict(_id integer primary key autoincrement , word , detail)";
* @param context
* @param name
* @param version
public MyDatabaseHelper(Context context, String name, int version)
super(context, name, null, version);
public void onCreate(SQLiteDatabase db)
// 第一个使用数据库时自动建表
db.execSQL(CREATE_TABLE_SQL);
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
System.out.println("--------onUpdate Called--------"
+ oldVersion + "---&" + newVersion);
package com.
import java.io.FileNotFoundE
import java.io.OutputS
import java.text.SimpleDateF
import java.util.D
import android.app.S
import android.content.C
import android.content.I
import android.database.sqlite.SQLiteD
import android.os.IB
import android.telephony.PhoneStateL
import android.telephony.TelephonyM
public class TtActivity extends Service
MyDatabaseHelper dbH
TelephonyManager tM
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String word=format.format(new Date());
public IBinder onBind(Intent intent)
return null;
public void onCreate()
tManager = (TelephonyManager) getSystemService
(Context.TELEPHONY_SERVICE);
dbHelper = new MyDatabaseHelper(this
, "myDict.db3" , 1);
// 创建一个通话状态监听器
PhoneStateListener listener = new PhoneStateListener()
public void onCallStateChanged(int state
, String detail)
switch (state)
// 无任何状态
case TelephonyManager.CALL_STATE_IDLE:
case TelephonyManager.CALL_STATE_OFFHOOK:
// 来电铃响时
case TelephonyManager.CALL_STATE_RINGING:
OutputStream os = null;
os = openFileOutput("phoneList", MODE_APPEND);
catch (FileNotFoundException e)
e.printStackTrace();
insertData(dbHelper.getReadableDatabase() , word , detail);
PrintStream ps = new PrintStream(os);
// 将来电号码记录到文件中
ps.println(new Date() + "
来电:" + incomingNumber);
ps.close();
super.onCallStateChanged(state, detail);
//监听电话通话状态的改变
tManager.listen(listener
, PhoneStateListener.LISTEN_CALL_STATE);
private void insertData(SQLiteDatabase db
, String word , String detail)
//执行插入语句
db.execSQL("insert into dict values(null , ? , ?)"
, new String[]{word , detail});
public void onDestroy()
super.onDestroy();
//退出程序时关闭MyDataBaseHelper里的SQLiteDatabase
if (dbHelper != null)
dbHelper.close();
package com.
import android.net.U
import android.provider.BaseC
* @version
public final class Words
// 定义该ContentProvider的Authority
public static final String AUTHORITY
= "org.crazyit.providers.dictprovider";
//定义一个静态内部类
public static final class Word implements BaseColumns
// 定义Content所允许操作的3个数据列
public final static String _ID = "_id";
public final static String WORD = "word";
public final static String DETAIL = "detail";
// 定义该Content提供服务的两个Uri
public final static Uri DICT_CONTENT_URI =
Uri.parse("content://" +
AUTHORITY + "/words");
public final static Uri WORD_CONTENT_URI =
Uri.parse("content://" +
AUTHORITY + "/word");
package com.
import android.content.ContentP
import android.content.ContentU
import android.content.ContentV
import android.content.UriM
import android.database.C
import android.database.sqlite.SQLiteD
import android.net.U
* @version
public class DictProvider extends ContentProvider
private static UriMatcher matcher
= new UriMatcher(UriMatcher.NO_MATCH);
private static final int WORDS = 1;
private static final int WORD = 2;
private MyDatabaseHelper dbOpenH
// 为UriMatcher注册两个Uri
matcher.addURI(Words.AUTHORITY, "words", WORDS);
matcher.addURI(Words.AUTHORITY, "word/#", WORD);
// 第一次调用该DictProvider时,系统先创建DictProvider对象,并回调该方法
public boolean onCreate()
dbOpenHelper = new MyDatabaseHelper(this.getContext(), "myDict.db3", 1);
return true;
// 插入数据方法
public Uri insert(Uri uri, ContentValues values)
// 获得数据库实例
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
// 插入数据,返回行ID
long rowId = db.insert("dict", Words.Word._ID, values);
// 如果插入成功返回uri
if (rowId & 0)
// 在已有的 Uri的后面追加ID数据
Uri wordUri = ContentUris.withAppendedId(uri, rowId);
// 通知数据已经改变
getContext().getContentResolver().notifyChange(wordUri, null);
return wordU
return null;
// 删除数据的方法
public int delete(Uri uri, String selection, String[] selectionArgs)
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
// 记录所删除的记录数
int num = 0;
// 对于uri进行匹配。
switch (matcher.match(uri))
case WORDS:
num = db.delete("dict", selection, selectionArgs);
case WORD:
// 解析出所需要删除的记录ID
long id = ContentUris.parseId(uri);
String where = Words.Word._ID + "=" +
// 如果原来的where子句存在,拼接where子句
if (selection != null && !selection.equals(""))
where = where + " and " +
num = db.delete("dict", where, selectionArgs);
throw new IllegalArgumentException("未知Uri:" + uri);
// 通知数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
// 修改数据的方法
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
// 记录所修改的记录数
int num = 0;
switch (matcher.match(uri))
case WORDS:
num = db.update("dict", values, selection, selectionArgs);
case WORD:
// 解析出想修改的记录ID
long id = ContentUris.parseId(uri);
String where = Words.Word._ID + "=" +
// 如果原来的where子句存在,拼接where子句
if (selection != null && !selection.equals(""))
where = where + " and " +
num = db.update("dict", values, where, selectionArgs);
throw new IllegalArgumentException("未知Uri:" + uri);
// 通知数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
// 查询数据的方法
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
switch (matcher.match(uri))
case WORDS:
// 执行查询
return db.query("dict", projection, selection, selectionArgs,
null, null, sortOrder);
case WORD:
// 解析出想查询的记录ID
long id = ContentUris.parseId(uri);
String where = Words.Word._ID + "=" +
// 如果原来的where子句存在,拼接where子句
if (selection != null && !"".equals(selection))
where = where + " and " +
return db.query("dict", projection, where, selectionArgs, null,
null, sortOrder);
throw new IllegalArgumentException("未知Uri:" + uri);
// 返回指定uri参数对应的数据的MIME类型
public String getType(Uri uri)
switch (matcher.match(uri))
// 如果操作的数据是多项记录
case WORDS:
return "vnd.android.cursor.dir/org.crazyit.dict";
// 如果操作的数据是单项记录
case WORD:
return "vnd.android.cursor.item/org.crazyit.dict";
throw new IllegalArgumentException("未知Uri:" + uri);
下面贴出第二个程序的代码,调用第一个程序ContentProvidler的接口
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="org.crazyit.resolver"
android:versionCode="1"
android:versionName="1.0"&
&application android:icon="@drawable/icon" android:label="@string/app_name"&
&activity android:name=".DictResolver"
android:label="@string/app_name"&
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&activity android:name=".ResultActivity"
android:theme="@android:style/Theme.Dialog"
android:label="找到的来电记录"&
&/activity&
&/application&
&/manifest&
package org.crazyit.
import android.net.U
import android.provider.BaseC
* @version
public final class Words
// 定义该ContentProvider的Authority
public static final String AUTHORITY
= "org.crazyit.providers.dictprovider";
//定义一个静态内部类
public static final class Word implements BaseColumns
// 定义Content所允许操作的3个数据列
public final static String _ID = "_id";
public final static String WORD = "word";
public final static String DETAIL = "detail";
// 定义该Content提供服务的两个Uri
public final static Uri DICT_CONTENT_URI =
Uri.parse("content://" +
AUTHORITY + "/words");
public final static Uri WORD_CONTENT_URI =
Uri.parse("content://" +
AUTHORITY + "/word");
package org.crazyit.
import java.util.ArrayL
import java.util.HashM
import java.util.M
import org.crazyit.content.W
import org.crazyit.resolver.R;
import android.app.A
import android.content.ContentR
import android.content.ContentV
import android.content.I
import android.database.C
import android.os.B
import android.view.V
import android.view.View.OnClickL
import android.widget.B
import android.widget.EditT
import android.widget.T
Yeeku.H.Lee
* @version
public class DictResolver extends Activity
ContentResolver contentR
Button search = null;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取系统的ContentResolver对象
contentResolver = getContentResolver();
search = (Button)findViewById(R.id.search);
// 为insert按钮的单击事件绑定事件监听器
search.setOnClickListener(new OnClickListener()
public void onClick(View source)
// 获取用户输入
String key = "";
// 执行查询
Cursor cursor = getContentResolver().query(
Words.Word.DICT_CONTENT_URI, null
//创建一个Bundle对象
Bundle data = new Bundle();
data.putSerializable("data", converCursorToList(cursor));
//创建一个Intent
Intent intent = new Intent(DictResolver.this
, ResultActivity.class);
intent.putExtras(data);
//启动Activity
startActivity(intent);
private ArrayList&Map&String, String&& converCursorToList(
Cursor cursor)
ArrayList&Map&String, String&& result
= new ArrayList&Map&String, String&&();
// 遍历Cursor结果集
while (cursor.moveToNext())
// 将结果集中的数据存入ArrayList中
Map&String, String& map = new HashMap&String, String&();
// 取出查询记录中第2列、第3列的值
map.put(Words.Word.WORD, cursor.getString(1));
map.put(Words.Word.DETAIL, cursor.getString(2));
result.add(map);
package org.crazyit.
import java.util.L
import java.util.M
import org.crazyit.content.W
import org.crazyit.resolver.R;
import android.app.A
import android.content.I
import android.os.B
import android.widget.ListV
import android.widget.SimpleA
* @version
public class ResultActivity extends Activity
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.popup);
ListView listView = (ListView)findViewById(R.id.show);
Intent intent = getIntent();
//获取该intent所携带的数据
Bundle data = intent.getExtras();
//从Bundle数据包中取出数据
@SuppressWarnings("unchecked")
List&Map&String , String&& list =
(List&Map&String , String&&)data.getSerializable("data");
//将List封装成SimpleAdapter
SimpleAdapter adapter = new SimpleAdapter(
ResultActivity.this , list
, R.layout.line , new String[]{Words.Word.WORD
, Words.Word.DETAIL}
, new int[]{R.id.word , R.id.detail});
//填充ListView
listView.setAdapter(adapter);
阅读(...) 评论()两个网站共用一个数据库怎么做?
[问题点数:40分]
两个网站共用一个数据库怎么做?
[问题点数:40分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2013年5月 总版技术专家分月排行榜第一
2014年8月 总版技术专家分月排行榜第二2014年7月 总版技术专家分月排行榜第二2013年6月 总版技术专家分月排行榜第二
2012年2月 PHP大版内专家分月排行榜第一2012年1月 PHP大版内专家分月排行榜第一2011年11月 PHP大版内专家分月排行榜第一2011年9月 PHP大版内专家分月排行榜第一
2012年3月 PHP大版内专家分月排行榜第二2011年12月 PHP大版内专家分月排行榜第二2011年10月 PHP大版内专家分月排行榜第二
2013年5月 总版技术专家分月排行榜第一
2014年8月 总版技术专家分月排行榜第二2014年7月 总版技术专家分月排行榜第二2013年6月 总版技术专家分月排行榜第二
本帖子已过去太久远了,不再提供回复功能。两个相同结构数据库,数据不同,如何把数据合并到一起。-mssql-电脑编程网两个相同结构数据库,数据不同,如何把数据合并到一起。作者:hld5511 和相关&&两个,表一样,字段名称也一样,只是数据不同。我现在想把这两个合并到一起。条件是保留其中一个数据库的ID字段不变,另一个数据ID字段递增方式复制过来。因为ID字段不可以有重复。希望有高手帮忙解答。------回答---------------其他回答(5分)---------另外一个数据字段递增还是有可能重复的------其他回答(5分)---------ID本身作用大吗如果只是个标识重新生成不可以吗------其他回答(5分)---------你是直接插入到一个数据库呢,还是做一个视图呢?不若做一个视图吧!合并------其他回答(5分)---------建立链接数据库,可以直接导入,选定字段,id不用选,直接导入就可以了!------回答---------------其他回答(5分)---------另外一个数据字段递增还是有可能重复的------其他回答(5分)---------ID本身作用大吗如果只是个标识重新生成不可以吗------其他回答(5分)---------你是直接插入到一个数据库呢,还是做一个视图呢?不若做一个视图吧!合并------其他回答(5分)---------建立链接数据库,可以直接导入,选定字段,id不用选,直接导入就可以了!相关资料:|||||||两个相同结构数据库,数据不同,如何把数据合并到一起。来源网络,如有侵权请告知,即处理!编程Tags:                &                    Oracle如何实现两个数据库的同步
Oracle如何实现两个数据库的同步
  我们经常希望把各地的数据入库后进行统一的应用。现在可以用复制技术来解决这个问题。但实现数据库复制也是要有一些条件的。
  首先,数据库要具备高级复制功能(用system身份登录数据库,查看v$option视图,如果其中Advanced replication为TRUE,则支持高级复制功能;否则不支持)。
  如果具备高级复制功能,数据库要进行一些参数初始化。
  db_domain = tes 指明数据库的域名(默认的是WORLD),这里可以用您公司的域名;global_names = true 它要求数据库链接(database link)和被连接的数据库名称一致,现在全局数据库名:db_name+”.”+db_domain ;
  跟数据库job执行有关的参数: job_queue_processes = 1; job_queue_interval = 60; distributed_transactions = 10; open_links = 4
  第一行定义SNP进程的启动个数为n。系统缺省值为0,正常定义范围为0~36,根据任务的多少,可以配置不同的数值。第二行定义系统每隔N秒唤醒该进程一次。系统缺省值为60秒,正常范围为1~3600秒。事实上,该进程执行完当前任务后,就进入睡眠状态,睡眠一段时间后,由系统的总控负责将其唤醒。如果修改了以上这几个参数,需要重新启动数据库以使参数生效。
  做完了初步的准备,我们来实现数据库同步复制。
  假设在Internet上有两个数据库:一个叫中国(China),一个叫日本(Japan)。 具体配置如下: 数据库名:China、Japan 数据库域名 tes 数据库sid号 China、Japan Listener端口号 1521 服务器ip地址 10.1.0.100 10.1.0.200 确认两个数据库之间可以互相访问,在tnsnames.ora里设置数据库连接字符串。 中国这边的数据库连接字符串是以下的格式: Japan = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.1.200)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = Japan) ) ) 运行$tnsping Japan,出现以下提示符: Attempting to contact (ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.200)(PORT=1521)) OK(n毫秒) 表明中国数据库可以访问日本数据库。在日本那边也同样配置,确认$tnsping China 是通的。 改数据库全局名称,建公共的数据库链接。 用system身份登录China数据库 SQL&alter database rename global_name to China. 用system身份登录Japan数据库: SQL&alter database rename global_name to J 用system身份登录China数据库。 SQL&create public database link Japa using 'Japan'; 测试数据库全局名称和公共的数据库链接。 SQL&select * from global_name@J 返回结果为Japa就对了。 用system身份登录Japan数据库: SQL&create public database link China.tes using 'China'; 测试数据库全局名称和公共的数据库链接。 SQL&select * from global_name@China. 返回结果为China.tes就对了。 建立管理数据库复制的用户repadmin,并赋权。 用system身份登录China数据库: SQL&create user repadmin identified by repadmin default tablespace users tempoSQL&execute dbms_defer_sys.register_propagator('repadmin'); SQL&grant execute any p SQL&execute dbms_repcat_admin.grant_admin_any_repgroup('repadmin'); SQL&grant comment a SQL&grant lock a 同样用system身份登录Japan数据库,运行以上的命令,管理数据库复制的用户repadmin,并赋权。 在数据库复制的用户repadmin下创建私有的数据库链接。 用repadmin身份登录China数据库。 SQL&create database link Japa connect to repadmin identified 试这个私有的数据库链接:SQL&select * from global_name@J 返回结果为Japa就对了。 用repadmin身份登录Japan数据库。 SQL&create database link China.tes connect to repadmin id测试这个私有的数据库链接: SQL&select * from global_name@China. 返回结果为China.tes就对了。 创建或选择实现数据库复制的用户和对象,给用户赋权,数据库对象必须有主关键字。 用internal身份登录China数据库,创建scott用户并赋权: SQL&create user scott identified by tiger default tablespace users tempoSQL&grant connect, SQL&grant execute on sys.dbms_ 用scott身份登录China数据库,创建表dept : SQL&create table dept (deptno number(2) primary key, dname varchar2(14), loc varchar2(13) ); 如果数据库对象没有主关键字,可以运行以下SQL命令添加: SQL&alter table dept add (constraint dept_deptno_pk primary key (deptno)); 在China数据库scott用户下创建主关键字的序列号,范围避免和Japan的冲突。 SQL& create sequence dept_no increment by 1 start with 1 maxvalue 44在China数据库scott用户下插入初始化数据 SQL&insert into dept values (dept_no.nextval,'accounting','new york'); SQL&insert into dept values (dept_no.nextval,'research','dallas'); SQL& 在Japan数据库那边同样运行以上①,②,③。 在Japan数据库scott用户下创建主关键字的序列号,范围避免和China的冲突。 SQL& create sequence dept_no increment by 1 start with 45 maxvalue 99在Japan数据库scott用户下插入初始化数据。 SQL&insert into dept values (dept_no.nextval,'sales','chicago'); SQL&insert into dept values (dept_no.nextval,'operations','boston'); SQL&实现Oracle数据库复制(二) 在Japan数据库那边同样运行以上①,②,③。 在Japan数据库scott用户下创建主关键字的序列号,范围避免和China的冲突。 SQL& create sequence dept_no increment by 1 start with 45 maxvalue 99在Japan数据库scott用户下插入初始化数据。 SQL&insert into dept values (dept_no.nextval,'sales','chicago'); SQL&insert into dept values (dept_no.nextval,'operations','boston'); SQL& 创建要复制的组scott_mg,加入数据库对象,产生对象的复制支持。 用repadmin身份登录China数据库,创建主复制组scott_mg: SQL& execute dbms_repcat.create_master_repgroup('scott_mg'); 在复制组scott_mg里加入数据库对象: SQL&execute dbms_repcat.create_master_repobject(sname=&'scott',oname=&'dept', type=&'table',use_existing_object=&true,gname=&'scott_mg');参数说明: sname 实现数据库复制的用户名称; oname 实现数据库复制的数据库对象名称; type 实现数据库复制的数据库对象类别; use_existing_object true表示用主复制节点已经存在的数据库对象; gname 主复制组名; 对数据库对象产生复制支持: SQL&execute dbms_repcat.generate_replication_support('scott','dept','table'); 确认复制的组和对象已经加入数据库的数据字典: SQL&select gname, master, status from dba_ SQL&select * from dba_ 创建主复制节点: 用repadmin身份登录China数据库,创建主复制节点: SQL&execute dbms_repcat.add_master_database (gname=&'scott_mg',master=&'Japa',use_existing_objects=&true, copy_rows=&false, propagation_mode =& 'asynchronous');参数说明: gname 主复制组名; master 加入主复制节点的另一个数据库; use_existing_object true表示用主复制节点已经存在的数据库对象; copy_rows false表示第一次开始复制时不用和主复制节点保持一致; propagation_mode 异步地执行; 确认复制的任务队列已经加入数据库的数据字典: SQL&select * from user_ 使同步组的状态由停顿(quiesced )改为正常(normal): 用repaa数据库,运行以下命令: SQL& execute dbms_repcat.resume_master_activity('scott_mg',false); 确认同步组的状态为正常(normal): SQL& select gname, master, status from dba_ 如果这个①命令不能使同步组的状态为正常(normal),可能有一些停顿的复制,运行以下命令再试试(建议在紧急的时候才用): SQL& execute dbms_repcat.resume_master_activity('scott_mg',true); 创建复制数据库的时间表,10分钟复制一次。 用repadmin身份登录China数据库,运行以下命令: SQL&begin dbms_defer_sys.schedule_push ( destination =& 'Japa', interval =& 'sysdate + 10/1440', next_date =& sysdate);
/ SQL&begin dbms_defer_sys.schedule_purge ( next_date =& sysdate, interval =& 'sysdate + 10/1440', delay_seconds =& 0, rollback_segment =& '');
/ 用repadmin身份登录Japan数据库,运行以下命令: SQL&begin dbms_defer_sys.schedule_push ( destination =& ' China.tes ', interval =& 'sysdate + 10 / 1440', next_date =& sysdate);
/ SQL&begin dbms_defer_sys.schedule_purge ( next_date =& sysdate, interval =& 'sysdate + 10/1440', delay_seconds =& 0, rollback_segment =& '');
/ 添加或修改两边数据库的记录,跟踪复制过程。如果你想立刻看到添加或修改后数据库的记录的变化,可以在两边repadmin用户下找到push的job_number,然后运行:SQL&exec dbms_job.run(job_number); 异常情况的处理: 检查复制工作正常否,可以在repadmin 用户下查询user_jobs SQL&select job,this_date,next_date,what, broken from user_ 正常的状态有两种:任务闲――this_date为空,next_date为当前时间后的一个时间值;任务忙――this_date不为空,next_date为当前时间后的一个时间值。异常状态也有两种:任务死锁――next_date为当前时间前的一个时间值;任务死锁――next_date为非常大的一个时间值,例如:。这可能因为网络中断照成的死锁。解除死锁的办法:$ps Cef|grep orale 找到死锁的刷新快照的进程号ora_snp*,用kill C9 命令删除此进程,然后进入repadmin 用户SQL&操作符下,运行命令: SQL&exec dbms_job.run(job_number); 说明:job_number 为用select job,this_date,next_date,what from user_命令查出的job编号。 增加或减少复制组的复制对象: 停止主数据库节点的复制动作,使同步组的状态由正常(normal)改为停顿(quiesced )。用repadmin身份登录China数据库,运行以下命令: SQL&execute dbms_repcat.suspend_master_activity (gname =& 'scott_mg'); 在复制组scott_mg里加入数据库对象,保证数据库对象必须有主关键字。 SQL&execute dbms_repcat.create_master_repobject(sname=&'scott',oname=&'emp', type=&'table',use_existing_object=&true,gname=&'scott_mg');对加入的数据库对象产生复制支持: SQL&execute dbms_repcat.generate_replication_support('scott','emp','table'); 在复制组scott_mg里删除数据库对象: SQL&execute dbms_repcat.drop_master_repobject ('scott','dept','table'); 重新使同步组的状态由停顿(quiesced )改为正常(normal)。 SQL& execute dbms_repcat.resume_master_activity('scott_mg',false);复制是一种实现数据分布的方法,也就是说把一个系统中的数据通过网络分布到另外一个或者多个地理位置不同的系统中,以适应可伸缩组织的需要、减轻主服务器的工作负荷和提高数据的使用效率。Ora Oracle8针对数据分布式计算的需要,提供了一整套功能强大的数据库复制解决方案。 Oracle8的数据复制按功能可以分为三类:基本(简单)复制、高级复制和混合复制,而高级复制又可分为多主节点复制和可更新快照复制。在 《数据复制中的定时任务机制》 介绍了Oracle8中的定时复制的机制,本文将主要介绍一个 Oracle 快照复制的实际例子及其技术实现细节。一、业务需求 在一个实际的数据库应用中,如银行、税务等商业应用中通常都采用这样一种解决方案,在一个行政区域内,如一个省或者一个市,在不同的地理位置架设数台数据库服务器,这些不同地理位置的服务器具有同样的后台数据库。为了维护数据库系统的一致性,对于整个行政区域应用的代码表应该保持一致,如果不考虑数据复制,想维护同样的不冲突的代码表是很困难的。下面是一个实际的业务需求,我们用这里例子来说明 Oracle快照复制的应用。为了维护整个系统代码表的一致性,客户提出了这样的业务需求,对于系统的代码表采用统一维护,即在一台服务器上维护,如图1所示。在位置1(数据库Ora_db1,用户userA)上维护代码表,其他位置(数据库ora_db2,用户userB;ora_db3,用户userC和ora_db4,用户UserD)可以直接使用这些代码表,也就是说在位置1具有对代码表插入、删除和更新的能力,而在其他地方只能有查询的能力。二、应用设计 针对上述的需求,我们提出了这样一种解决方案,也就是采用 Oracle8的快照复制。具体业务实现方案设计如下: 在位置1的数据库Ora_db1维护所有的代码表,在其余数据库建立相对于位置1的所有代码表的快照。为了维护快照的方便,在位置2、3和4创建一个单独的快照表空间和一个模式(schema),系统中的其他用户通过一个私有同义词来存取这些快照。这里私有同义词相对公共同义词要好,这是因为在位置1存在一个同样规范的系统,它的表是通过公共同义词来存取的。对于快照的刷新,采用 Oracle系统包DBMS-_REFRESH进行,并将该刷新过程的运行定时在每天早上2:00,这样可以减少网络流量。对于快照的刷新形式,由于对于代码表的维护不是很多而且代码表的数据量相对较少,所以在此选择了完全刷新,这样就避免了管理快照日志的麻烦。下面以一个节点2(ora_db2)为例来说明具体的技术实现细节。三、技术实现细节 除非特别说明,下面的SQL命令都是在数据库ora_db2的SYSETM用户下运行的。假设要复制的代码表有三个:dm_gy_rydm,dm_gy_jgdm和dm_gy_yhdm。1.在数据库2(ora_db2)上增加数据库1(ora_db1)的services name 可以直接在tnsnames.ora文件中增加数据库1的services name,包括IP地址,SID以及端口号等。Services name 命名为ora_db1.world。2. 创建一个用于连接数据库1(ora_db1)的数据库连接(dblink) SQL& CREATE PUBLIC DATABASE LINK ora_db1.world CONNECT TO SYSTEM IDENTIFIED BY MANAGER USING 'ora_db1.world';&&出于安全考虑,可以采用一个私有数据连接。 3. 创建一个名为Snapshot_ts的表空间来存放快照,并创建一个和该表空间有关的名为Snap的用户。 SQL & CREATE TABLESPACE snapshot_ts DATAFILE 'c:\orant\dbfiles\prod\snapshot01.dbf' SIZE 30M DEFAULT STORAGE (INITIAL 30 K NEXT 15 K MINEXTENTS 1 MAXEXTENTS 100 PCTINCREASE 0) ONLINE PERMANENT;&&SQL & CREATE USER snap IDENTIFIED BY snap DEFAULT TABLESPACE snapshot_&&SQL & GRANT CONNECT, RESOURCE TO&&可以通过下面的SQL语句在ora_db1数据库以userA用户来粗略地估计表空间snapshot_ts的大小。 SQL & SELECT SUM(bytes) FROM USER_SEGMENTS WHERE SEGMENT_NAME IN (' dm_gy_rydm', 'dm_gy_jgdm', 'dm_gy_yhdm');&&4. 运行下面的脚本文件snapsql.sql来生成创建ora_db1数据库上userA用户下代码表的快照脚本: /* Snapsql.sql */ spool c:\snap\create_snapshot.sql SELECT 'CREATE SNAPSHOT SNAP.' || TABLE_NAME || ' PCTFREE 10 PCTUSED 40 TABLESPACE snapshot_ts ' || ' STORAGE (INITIAL ' || INITIAL_EXTENT || ' NEXT ' || NEXT_EXTENT || ' PCTINCREASE 0 )' || ' AS SELECT * FROM userA.' || TABLE_NAME || '@ora_db1.' FROM USER_TABLES WHERE TABLE_NAME IN( (' dm_gy_rydm', 'dm_gy_jgdm', 'dm_gy_yhdm'); spool off&&注意上面这个生成所需表快照的脚本有一定的局限性,如果所需生成快照的表中含有类型为long的列,‘select *'在这里就不会起作用,上面的这个SQL脚本就不能自动建立生成所需快照的脚本,必须通过在select列表中显式地添加long型列名来创建表的快照。下面是一个例子,假如我们要创建快照依赖的表dm_gy_note中有一个列note类型为long,就需要单独写出如下的创建快照的脚本:CREATE SNAPSHOT snap.dm_gy_note PCTFREE 10 PCTUSED 40 TABLESPACE snapcost_ts STORAGE (INITIAL 40960 NEXT 57344 PCTINCREASE 0 ) AS SELECT dm, dmmc,note FROM userA.dm_gy_note@ora_db1. SQL & @snapsql.sql&&5. 通过运行第4步创建的脚本文件create_snapshot.sql来创建所有的快照, 在脚本文件中包含下面这样的代码: CREATE SNAPSHOT snap. dm_gy_rydm PCTFREE 10 PCTUSED 40 TABLESPACE snapshot_ts STORAGE (INITIAL 163840 NEXT 57344 PCTINCREASE 0) AS SELECT * FROM userA. dm_gy_rydm @ora_db1.&&运行脚本文件create_snapshot.sql后,就在模式snap中创建了所需要的快照。下一步就是考虑该如何刷新快照。对于快照的刷新,可以通过一些桌面DBA工具来刷新快照也可以通过系统包dbms_snapshot.refresh来刷新一个快照:SQL & EXECUTE DBMS_SNAPSHOT.REFRESH ('snap.dm_gy_rydm')&&6. 创建一个定时刷新过程来定时刷新快照: /*sp_snapshot_refresh.sql */ CREATE OR REPLACE PROCEDURE sp_snapshot_refresh IS BEGIN DBMS_REFRESH.MAKE ( NAME=&'tax_dmb_grp', LIST=&'snap. dm_gy_rydm, 'snap.dm_gy_jgdm', 'snap.dm_gy_yhdm', NEXT_DATE=&TRUNC (SYSDATE+1)+2/24, INTERVAL=&'(SYSDATE+1)', IMPLICIT_DESTROY=&FALSE, LAX=&TRUE); END; / SQL & EXECUTE sp_snapshot_refresh&&这样就创建了一个定时任务来每天早晨2:00定时刷新快照。运行下面的SQL语句就可以看到刚刚加入的这个任务。 SQL & SELECT JOB, WHAT FROM DBA_JOBS;&&7. 在用户userB下创建快照的私有同义词: SQL & CREATE SYNONYM userB.dm_gy_rydm FOR snap.dm_gy_&&8. 以Snap用户向userB用户授与快照可以select的权限。 SQL & GRANT SELECT ON dm_gy_rydm TO userB;&&同样的步骤在位置3(ora_db2)和位置4(ora_db3)建立位置1(ora_db1)的代码表快照和定时刷新任务。这样就可实现在位置1统一维护代码表,在位置2、3和4使用该代码表的目的。如下面的SQL语句,在位置2(ora_db2)用户UserB浏览在位置1(ora_db1)中的代码表。SQL & SELECT * FROM dm_gy_&&四、日常维护 无论任何时候只要出现网络连接问题,刷新就会失败。这些错误信息可以在alert log文件中找到。下面简单介绍一下对这种问题的处理办法: 1. 首先在任务队列中找到刷新快照的的任务编号 SQL & SELECT JOB,what FROM DBA_JOBS;&&2. 删除该任务 SQL & EXECUTE DBMS_JOB.REMOVE (JOBNO);&&3. 删除快照组 SQL & EXECUTE DBMS_REFRESH.DESTROY ('tax_dmb_grp');&&4. 重新创建快照组并且重新定时任务来定时刷新快照 SQL & EXECUTE sp_snapshot_refresh&&五、快照监视 快照可以通过下面的SQL语句来监视 SQL & SELECT NAME, TO_CHAR(last_refresh,'DD-MON-YY HH:MM:SS') FROM DBA_SNAPSHOTS;&&
&&&主编推荐
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
港口与航道工程建设工程法规及相关知识建设工程经济考试大纲矿业工程市政公用工程通信与广电工程
操作系统汇编语言计算机系统结构人工智能数据库系统微机与接口
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
Powerpoint教程WPS教程
电子政务客户关系管理首席信息官办公自动化大数据
职称考试题目
就业指导签约违约职业测评
招生信息考研政治
网络安全安全设置工具使用手机安全
3DMax教程Flash教程CorelDraw教程Director教程
Dreamwaver教程HTML教程网站策划网站运营Frontpage教程
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
互联网电信IT业界IT生活
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
组织运营财务资本
视频播放文件压缩杀毒软件输入法微博
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-}

我要回帖

更多关于 实现一个数据库 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信