精华内容
下载资源
问答
  • 那我来演示下如何使用RG。 创建一个资源组user_ytt. 这里解释下各个参数的含义, type = user 表示这是一个用户态线程,也就是前台的请求线程。如果type=system,表示后台线程,用来限制mysql自己的线程,比如...

    设置max_execution_time 来阻止太长的读SQL。那可能存在的问题是会把所有长SQL都给KILL 掉。有些必须要执行很长时间的也会被误杀。

    自己写个脚本检测这类语句,比如order by rand(), 超过一定时间用Kill query thread_id 给杀掉。

    那能不能不要杀掉而让他正常运行,但是又不影响其他的请求呢?

    那mysql 8.0 引入的资源组(resource group,后面简写微RG)可以基本上解决这类问题。

    比如我可以用 RG 来在SQL层面给他限制在特定的一个CPU核上,这样我就不管他,让他继续运行,如果有新的此类语句,让他排队好了。

    为什么说基本呢?目前只能绑定CPU资源,其他的暂时不行。

    那我来演示下如何使用RG。

    创建一个资源组user_ytt. 这里解释下各个参数的含义,

    type = user 表示这是一个用户态线程,也就是前台的请求线程。如果type=system,表示后台线程,用来限制mysql自己的线程,比如Innodb purge thread,innodb read thread等等。

    vcpu 代表cpu的逻辑核数,这里0-1代表前两个核被绑定到这个RG。可以用lscpu,top等列出自己的CPU相关信息。

    thread_priority 设置优先级。user 级优先级设置大于0。

    mysqlmysql> create resource group user_ytt type = user  vcpu = 0-1 thread_priority=19 enable;Query OK, 0 rows affected (0.03 sec)

    RG相关信息可以从 information_schema.resource_groups 系统表里检索。

    mysqlmysql> select * from information_schema.resource_groups;+---------------------+---------------------+------------------------+----------+-----------------+| RESOURCE_GROUP_NAME | RESOURCE_GROUP_TYPE | RESOURCE_GROUP_ENABLED | VCPU_IDS | THREAD_PRIORITY |+---------------------+---------------------+------------------------+----------+-----------------+| USR_default         | USER                |                      1 | 0-3      |               0 || SYS_default         | SYSTEM              |                      1 | 0-3      |               0 || user_ytt            | USER                |                      1 | 0-1      |              19 |+---------------------+---------------------+------------------------+----------+-----------------+3 rows in set (0.00 sec)

    我们来给语句select guid from t1 group by left(guid,8) order by rand() 赋予RG user_ytt。

    mysql> show processlist;+-----+-----------------+-----------+------+---------+-------+------------------------+-----------------------------------------------------------+| Id  | User            | Host      | db   | Command | Time  | State                  | Info                                                      |+-----+-----------------+-----------+------+---------+-------+------------------------+-----------------------------------------------------------+|   4 | event_scheduler | localhost | NULL | Daemon  | 10179 | Waiting on empty queue | NULL                                                      || 240 | root            | localhost | ytt  | Query   |   101 | Creating sort index    | select guid from t1 group by left(guid,8) order by rand() || 245 | root            | localhost | ytt  | Query   |     0 | starting               | show processlist                                          |+-----+-----------------+-----------+------+---------+-------+------------------------+-----------------------------------------------------------+3 rows in set (0.00 sec)

    找到连接240对应的thread_id。

    mysqlmysql> select thread_id from performance_schema.threads where processlist_id = 240;+-----------+| thread_id |+-----------+|       278 |+-----------+1 row in set (0.00 sec)

    给这个线程278赋予RG user_ytt。没报错就算成功了。

    mysqlmysql> set resource group user_ytt for 278;Query OK, 0 rows affected (0.00 sec)

    当然这个是在运维层面来做的,我们也可以在开发层面结合 MYSQL HINT 来单独给这个语句赋予RG。比如:

    mysqlmysql> select /*+ resource_group(user_ytt) */guid from t1 group by left(guid,8) order by rand()....8388602 rows in set (4 min 46.09 sec)

    RG的限制:

    Linux 平台上需要开启 CAPSYSNICE 特性。比如我机器上用systemd 给mysql 服务加上

    systemctl edit mysql@80 [Service]AmbientCapabilities=CAP_SYS_NICE

    mysql 线程池开启后RG失效。

    freebsd,solaris 平台thread_priority 失效。

    目前只能绑定CPU,不能绑定其他资源。

    展开全文
  • 1前提 很多时候我们都是在主线程下直接打开数据库并...大家都知道,在多线程操作数据库的时候,如果在各自线程中都利用之前的方法:实例化一个SQLiteOpenHelper类,然后在调用其中的方法。后面的就会遇到android.databa

    前提

    很多时候我们都是在主线程下直接打开数据库并对数据库操作的,但如果遇到加密型的数据库,例如SQLCipher加密数据库,或者是对字段进行加密的数据库;你就不得不在线程里面操作数据库了!

    解决

    大家都知道,在多线程操作数据库的时候,如果在各自线程中都利用之前的方法:实例化一个SQLiteOpenHelper类,然后在调用其中的方法。后面的就会遇到android.database.sqlite.SQLiteException: database is locked这样的异常。原因当然就是多线程的时候,导致的关闭异常,例如A线程的一个查询操作,在打开了数据库后,被B线程close了,导致A线程报错。要解决一样的问题,安全一点的方法是利用单例的形式创建SQLiteOpenHelper类或者是实现是具体数据库增删改查的Dao类,并且对方法添加synchronizaed关键字。
    关键代码:StuDao 包含了对数据库的操作语句,在方法上都加上了锁
    package com.lingdududu.testSQLiteDao;
    
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.os.Build;
    import android.util.Log;
    
    import com.lingdududu.testSQLiteDb.StuDBHelper;
    
    public class StuDao {
    
    	// 创建StuDBHelper对象
    	StuDBHelper dbHelper = null;
    	// 得到一个可读的SQLiteDatabase对象
    	SQLiteDatabase db = null;
    	Cursor cursor = null;
    	static StuDao stuDao = null;
    
    	private String TABLE = "stu_table";
    	private String TAG = "StuDao";
    
    	static Object lock = new Object();
    
    	public static StuDao getInstance(Context context) {
    		if (stuDao == null) {
    			synchronized (lock) {
    				if (stuDao == null) {
    					stuDao = new StuDao(context);
    				}
    			}
    		}
    		return stuDao;
    	}
    
    	public void destoryDB() {
    		// 关闭数据库
    		close();
    		stuDao = null;
    	}
    
    	private StuDao(Context context) {
    		Log.e(TAG, "--->>>   StuDao");
    		dbHelper = new StuDBHelper(context, "stu_db", null, 1);
    		if (Build.VERSION.SDK_INT >= 11) {
    			dbHelper.getWritableDatabase().enableWriteAheadLogging();
    		}
    	}
    
    	Object queryLock = new Object();
    
    	public synchronized void queryTable() {
    		// 得到一个可写的数据库
    		db = dbHelper.getWritableDatabase();
    		// 参数1:表名
    		// 参数2:要想显示的列
    		// 参数3:where子句
    		// 参数4:where子句对应的条件值
    		// 参数5:分组方式
    		// 参数6:having条件
    		// 参数7:排序方式
    		cursor = db.query(TABLE,
    				new String[] { "id", "sname", "sage", "ssex" }, null, null,
    				null, null, null);
    		while (cursor.moveToNext()) {
    			String name = cursor.getString(cursor.getColumnIndex("sname"));
    			String age = cursor.getString(cursor.getColumnIndex("sage"));
    			String sex = cursor.getString(cursor.getColumnIndex("ssex"));
    			int id = cursor.getInt(cursor.getColumnIndex("id"));
    			System.out.println("query------->" + "id:" + id + " " + "姓名:"
    					+ name + " " + "年龄:" + age + " " + "性别:" + sex);
    		}
    		// 关闭数据库
    		this.close();
    
    	}
    
    	public synchronized void queryTable(int id) {
    		// 得到一个可写的数据库
    		db = dbHelper.getWritableDatabase();
    		// 参数1:表名
    		// 参数2:要想显示的列
    		// 参数3:where子句
    		// 参数4:where子句对应的条件值
    		// 参数5:分组方式
    		// 参数6:having条件
    		// 参数7:排序方式
    		cursor = db.query(TABLE,
    				new String[] { "id", "sname", "sage", "ssex" }, "id=?",
    				new String[] { Integer.toString(id) }, null, null, null);
    		while (cursor.moveToNext()) {
    			String name = cursor.getString(cursor.getColumnIndex("sname"));
    			String age = cursor.getString(cursor.getColumnIndex("sage"));
    			String sex = cursor.getString(cursor.getColumnIndex("ssex"));
    			int sid = cursor.getInt(cursor.getColumnIndex("id"));
    			Log.d(TAG, "id:" + sid + " " + "姓名:" + name + " " + "年龄:" + age
    					+ " " + "性别:" + sex);
    		}
    		// 关闭数据库
    		this.close();
    	}
    
    	public synchronized void updateTable(String id, String sage) {
    		// 得到一个可写的数据库
    		db = dbHelper.getWritableDatabase();
    		ContentValues cv = new ContentValues();
    		cv.put("sage", sage);
    		cv.put("id", id);
    		// where 子句 "?"是占位符号,对应后面的"1",
    		String whereClause = "id=?";
    		String[] whereArgs = { String.valueOf(id) };
    		// 参数1 是要更新的表名
    		// 参数2 是一个ContentValeus对象
    		// 参数3 是where子句
    		db.update(TABLE, cv, whereClause, whereArgs);
    		// 关闭数据库
    		this.close();
    	}
    
    	public synchronized void insertTable(String id, String sage) {
    		// 得到一个可写的数据库
    		db = dbHelper.getWritableDatabase();
    		// 生成ContentValues对象 //key:列名,value:想插入的值
    		ContentValues cv = new ContentValues();
    		// 往ContentValues对象存放数据,键-值对模式
    		cv.put("id", id);
    		cv.put("sname", "xiaoming");
    		cv.put("sage", sage);
    		cv.put("ssex", "male");
    		// 调用insert方法,将数据插入数据库
    		db.insert("stu_table", null, cv);
    		// 关闭数据库
    		// 关闭数据库
    		this.close();
    	}
    
    	public synchronized void deleteTable(int id) {
    		// 得到一个可写的数据库
    		db = dbHelper.getWritableDatabase();
    		String whereClauses = "id=?";
    		String[] whereArgs = { String.valueOf(id) };
    		// 调用delete方法,删除数据
    		db.delete(TABLE, whereClauses, whereArgs);
    		// 关闭数据库
    		this.close();
    	}
    
    	public synchronized void deleteTable() {
    		// db = dbHelper.getWritableDatabase();
    		// String sql = "drop table if exists "+TABLE;
    		// db.execSQL(sql);
    
    		// 得到一个可写的数据库
    		db = dbHelper.getWritableDatabase();
    		// 调用delete方法,删除数据
    		db.delete(TABLE, null, null);
    
    		// 关闭数据库
    		this.close();
    	}
    
    	public void close() {
    		if (db != null) {
    			db.close();
    		}
    		if (cursor != null) {
    			cursor.close();
    		}
    	}
    
    }

    在SQLiteActivityMulThread开启线程操作数据库:
    package com.lingdududu.testSQLite;
    
    import com.lingdududu.MyThreadPoolExecutor;
    import com.lingdududu.testSQLiteDao.StuDao;
    import com.lingdududu.testSQLiteDb.StuDBHelper;
    
    import android.app.Activity;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    /*
     * @author lingdududu
     */
    public class SQLiteActivityMulThread extends Activity {
    	/** Called when the activity is first created. */
    	// 声明各个按钮
    	private Button insertDatabase;
    	private Button updateDatabase1;
    	private Button updateDatabase2;
    	private Button deleteDatabase;
    
    	int age;
    	int id = 100;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main_mul);
    
    		// 调用creatView方法
    		creatView();
    		setListener();
    		// MyThreadPoolExecutor.getInstance().execute(new Runnable() {
    		//
    		// @Override
    		// public void run() {
    		// StuDao.getInstance(SQLiteActivityMulThread.this).queryTable();
    		// }
    		// });
    		// for (age = 0; age < 10; age++) {
    		// MyThreadPoolExecutor.getInstance().execute(new Runnable() {
    		// @Override
    		// public void run() {
    		// StuDao.getInstance(SQLiteActivityMulThread.this)
    		// .updateTable(Integer.toString(age));
    		// }
    		// });
    		// }
    
    	}
    
    	@Override
    	protected void onDestroy() {
    		StuDao.getInstance(SQLiteActivityMulThread.this).destoryDB();
    		super.onDestroy();
    	}
    
    	// 通过findViewById获得Button对象的方法
    	private void creatView() {
    		insertDatabase = (Button) findViewById(R.id.insertDatabase);
    		updateDatabase1 = (Button) findViewById(R.id.updateDatabase1);
    		updateDatabase2 = (Button) findViewById(R.id.updateDatabase2);
    		deleteDatabase = (Button) findViewById(R.id.deleteDatabase);
    	}
    
    	// 为按钮注册监听的方法
    	private void setListener() {
    		insertDatabase.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				// insertTable
    				id = 100;
    				for (; id < 120; id++) {
    					final int sid = id;
    					// System.out.println("------sid----"+sid);
    					// System.out.println("------id----"+id);
    					MyThreadPoolExecutor.getInstance().execute(new Runnable() {
    
    						@Override
    						public void run() {
    							StuDao.getInstance(SQLiteActivityMulThread.this)
    									.insertTable(Integer.toString(sid),
    											Integer.toString(sid));
    							StuDao.getInstance(SQLiteActivityMulThread.this)
    									.queryTable(sid);
    						}
    					});
    				}
    			}
    
    		});
    		updateDatabase1.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				id = 100;
    				// updateTable
    				for (; id < 120; id++) {
    					final int sid = id;
    					// System.out.println("------sid----"+sid);
    					// System.out.println("------id----"+id);
    					MyThreadPoolExecutor.getInstance().execute(new Runnable() {
    
    						@Override
    						public void run() {
    							StuDao.getInstance(SQLiteActivityMulThread.this)
    									.updateTable(Integer.toString(sid),
    											Integer.toString(sid * 2));
    							StuDao.getInstance(SQLiteActivityMulThread.this)
    									.queryTable(sid);
    						}
    					});
    					// MyThreadPoolExecutor.getInstance().execute(new Runnable()
    					// {
    					//
    					// @Override
    					// public void run() {
    					// StuDao.getInstance(SQLiteActivityMulThread.this).deleteTable(id);
    					// }
    					// });
    				}
    			}
    		});
    		updateDatabase2.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				id = 100;
    				for (; id < 120; id++) {
    					final int sid = id;
    					// System.out.println("------sid----"+sid);
    					// System.out.println("------id----"+id);
    					MyThreadPoolExecutor.getInstance().execute(new Runnable() {
    
    						@Override
    						public void run() {
    							StuDao.getInstance(SQLiteActivityMulThread.this)
    									.updateTable(Integer.toString(sid),
    											Integer.toString(sid * 3));
    							StuDao.getInstance(SQLiteActivityMulThread.this)
    									.queryTable(sid);
    						}
    					});
    					// MyThreadPoolExecutor.getInstance().execute(new Runnable()
    					// {
    					//
    					// @Override
    					// public void run() {
    					// StuDao.getInstance(SQLiteActivityMulThread.this).deleteTable(id);
    					// }
    					// });
    				}
    			}
    
    		});
    		deleteDatabase.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				MyThreadPoolExecutor.getInstance().execute(new Runnable() {
    
    					@Override
    					public void run() {
    						StuDao.getInstance(SQLiteActivityMulThread.this)
    								.deleteTable();
    					}
    				});
    			}
    
    		});
    
    	}
    
    	// 创建数据库的方法
    	class CreateListener implements OnClickListener {
    
    		@Override
    		public void onClick(View v) {
    			// 创建StuDBHelper对象
    			StuDBHelper dbHelper = new StuDBHelper(
    					SQLiteActivityMulThread.this, "stu_db", null, 1);
    			// 得到一个可读的SQLiteDatabase对象
    			SQLiteDatabase db = dbHelper.getReadableDatabase();
    		}
    	}
    
    	// 更新数据库的方法
    	class UpdateListener implements OnClickListener {
    
    		@Override
    		public void onClick(View v) {
    			// 数据库版本的更新,由原来的1变为2
    			StuDBHelper dbHelper = new StuDBHelper(
    					SQLiteActivityMulThread.this, "stu_db", null, 2);
    			SQLiteDatabase db = dbHelper.getReadableDatabase();
    		}
    	}
    
    	// 插入数据的方法
    	class InsertListener implements OnClickListener {
    
    		@Override
    		public void onClick(View v) {
    
    			StuDBHelper dbHelper = new StuDBHelper(
    					SQLiteActivityMulThread.this, "stu_db", null, 1);
    			// 得到一个可写的数据库
    			SQLiteDatabase db = dbHelper.getWritableDatabase();
    
    			// 生成ContentValues对象 //key:列名,value:想插入的值
    			ContentValues cv = new ContentValues();
    			// 往ContentValues对象存放数据,键-值对模式
    			cv.put("id", 1);
    			cv.put("sname", "xiaoming");
    			cv.put("sage", 21);
    			cv.put("ssex", "male");
    			// 调用insert方法,将数据插入数据库
    			db.insert("stu_table", null, cv);
    			// 关闭数据库
    			db.close();
    		}
    	}
    
    	// 查询数据的方法
    	class QueryListener implements OnClickListener {
    
    		@Override
    		public void onClick(View v) {
    
    			StuDBHelper dbHelper = new StuDBHelper(
    					SQLiteActivityMulThread.this, "stu_db", null, 1);
    			// 得到一个可写的数据库
    			SQLiteDatabase db = dbHelper.getReadableDatabase();
    			// 参数1:表名
    			// 参数2:要想显示的列
    			// 参数3:where子句
    			// 参数4:where子句对应的条件值
    			// 参数5:分组方式
    			// 参数6:having条件
    			// 参数7:排序方式
    			Cursor cursor = db.query("stu_table", new String[] { "id", "sname",
    					"sage", "ssex" }, "id=?", new String[] { "1" }, null, null,
    					null);
    			while (cursor.moveToNext()) {
    				String name = cursor.getString(cursor.getColumnIndex("sname"));
    				String age = cursor.getString(cursor.getColumnIndex("sage"));
    				String sex = cursor.getString(cursor.getColumnIndex("ssex"));
    				System.out.println("query------->" + "姓名:" + name + " " + "年龄:"
    						+ age + " " + "性别:" + sex);
    			}
    			// 关闭数据库
    			db.close();
    		}
    	}
    
    	// 修改数据的方法
    	class ModifyListener implements OnClickListener {
    
    		@Override
    		public void onClick(View v) {
    
    			StuDBHelper dbHelper = new StuDBHelper(
    					SQLiteActivityMulThread.this, "stu_db", null, 1);
    			// 得到一个可写的数据库
    			SQLiteDatabase db = dbHelper.getWritableDatabase();
    			ContentValues cv = new ContentValues();
    			cv.put("sage", "100");
    			// where 子句 "?"是占位符号,对应后面的"1",
    			String whereClause = "id=?";
    			String[] whereArgs = { String.valueOf(1) };
    			// 参数1 是要更新的表名
    			// 参数2 是一个ContentValeus对象
    			// 参数3 是where子句
    			db.update("stu_table", cv, whereClause, whereArgs);
    		}
    	}
    
    	// 删除数据的方法
    	class DeleteListener implements OnClickListener {
    
    		@Override
    		public void onClick(View v) {
    
    			StuDBHelper dbHelper = new StuDBHelper(
    					SQLiteActivityMulThread.this, "stu_db", null, 1);
    			// 得到一个可写的数据库
    			SQLiteDatabase db = dbHelper.getReadableDatabase();
    			String whereClauses = "id=?";
    			String[] whereArgs = { String.valueOf(2) };
    			// 调用delete方法,删除数据
    			db.delete("stu_table", whereClauses, whereArgs);
    		}
    	}
    }

    实现自己的线程池:
    package com.lingdududu;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    //	ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 200, TimeUnit.MILLISECONDS,
    //            new LinkedBlockingQueue<Runnable>() );
    
    public class MyThreadPoolExecutor implements Executor {
    
    	private static final int CORE_POOL_SIZE = 5;
    	private static final int MAXIMUM_POOL_SIZE = 256;
    	private static final int KEEP_ALIVE = 1;
    
    	private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    		private final AtomicInteger mCount = new AtomicInteger(1);
    
    		@Override
    		public Thread newThread(Runnable r) {
    			return new Thread(r, "MyThreadPoolExecutor #"
    					+ mCount.getAndIncrement());
    		}
    	};
    
    	private final ThreadPoolExecutor mThreadPoolExecutor;
    	private static MyThreadPoolExecutor mExecutor;
    
    	public static MyThreadPoolExecutor getInstance() {
    		if (mExecutor == null) {
    			return new MyThreadPoolExecutor(CORE_POOL_SIZE);
    		}
    		return mExecutor;
    	}
    
    	public MyThreadPoolExecutor getInstance(int poolSize) {
    		if (mExecutor == null) {
    			return new MyThreadPoolExecutor(poolSize);
    		}
    		return mExecutor;
    	}
    
    	private MyThreadPoolExecutor() {
    		this(CORE_POOL_SIZE);
    	}
    
    	private MyThreadPoolExecutor(int poolSize) {
    		mThreadPoolExecutor = new ThreadPoolExecutor(poolSize,
    				MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS,
    				new LinkedBlockingQueue<Runnable>(), sThreadFactory);
    	}
    
    	public int getPoolSize() {
    		return mThreadPoolExecutor.getCorePoolSize();
    	}
    
    	public void setPoolSize(int poolSize) {
    		if (poolSize > 0) {
    			mThreadPoolExecutor.setCorePoolSize(poolSize);
    		}
    	}
    
    	public boolean isBusy() {
    		return mThreadPoolExecutor.getActiveCount() >= mThreadPoolExecutor
    				.getCorePoolSize();
    	}
    
    	@Override
    	public void execute(final Runnable r) {
    		mThreadPoolExecutor.execute(r);
    	}
    }
    

    不知道大家有没发现在上述的获取数据库的方法中,我都用统一用了getWritableDatabase(),原因是如果在升级了数据库后,如果删除了某一张表,又恰好是利用getReadableDatabase()的方式打开数据库的话,将会报错因为没权限创建修改数据库。详情看我的博客http://blog.csdn.net/u011484134/article/details/49795991
     对于后面这个问题,我暂时也没想到好的办法解决,欢迎大家讨论!

    源码



    展开全文
  • 如何让多进程多线程访问数据库,而不会选择相同的数据,这在设计分布式程序的时候经常用到,多台机器的多个进程,每个进程都有多个线程,每个线程要从数据库里取数据来处理,要实现不能漏取数据,也不能重复取数据,...

    如何让多进程多线程访问数据库,而不会选择相同的数据,这在设计分布式程序的时候经常用到,多台机器的多个进程,每个进程都有多个线程,每个线程要从数据库里取数据来处理,要实现不能漏取数据,也不能重复取数据,这里给出答案

    创建一个数据表,如下,一个自增列,一个表示rss链接地址先放1w条数据再创建一个锁表,一个字段表示是否已经锁定的资源,另一个表示已经读取的rss源的最大id初始化数据下面我们要设计一个存储过程,让这个存储过程每次返回10个rss源,知道返回所有的rss源,要求无遗漏,无重复返回。如下1、如果锁表里显示没有进程正在读取rss源(IsLock = 0),那么就返回从最大的rss源id往后的10个rss源,否则返回空。

    2、用with(READPAST)表示忽略锁住的行,如果另一个进程正在执行update Rss_RssSourceLock的语句,并且在事务提交前,update语句会锁住这些要更新的行,而Rss_RssSourceLock表就一行数据,这时候select Rss_RssSourceLock表并且忽略被锁的行肯定是没数据的,所以本次存储过程执行会返回空。

    3、begin tran和commit tran保证了即使本次存储过程出错,也不会让Rss_RssSourceLock表处于IsLock = 1的脏数据状态,如果处于这种状态,后面的进程执行存储过程就永远也返回不了数据了。

    4、因为有时候一次选取的记录可能不够10条,所以这里用了个临时表来暂存记录,再算出来选取的条数,最后更新Rss_RssSourceLock表的MaxSourceId字段。但用临时表肯定会增加数据库的压力,这里不知道用表变量是不是会改善性能,暂时先这样了。

    5、应用里调用这个存储过程,如果返回了数据,就进行处理,如果没返回数据,就sleep几秒才执行,直到返回数据。

    CREATE TABLE [dbo].[Rss_RssSources](

    [SourceId] [int] IDENTITY(1,1) NOT NULL,

    [Link] [varchar](1024) NOT NULL

    ) ON [PRIMARY]

    declare @i int

    set @i = 1

    while @i <10000

    begin

    select @i = @i +1

    insert into [Rss_RssSources] values(newid())

    end

    create table Rss_RssSourceLock

    (

    IsLock bit,

    MaxSourceId int

    )

    insert into Rss_RssSourceLock values (0,0)

    CREATE PROCEDURE [dbo].[USP_GetRssSources]

    AS

    BEGIN

    if exists(select * from Rss_RssSourceLock with(READPAST) where IsLock = 0)

    begin

    declare @select_count int

    begin tran

    update Rss_RssSourceLock set IsLock = 1

    if object_id('tempdb..#t') is not null

    drop table #t

    select top 10 a.* into #t from [Rss_RssSources] as a

    inner join Rss_RssSourceLock as b

    on a.SourceId > b.MaxSourceId

    order by a.[SourceId]

    select @select_count = count(*) from #t

    update Rss_RssSourceLock set IsLock = 0,MaxSourceId = MaxSourceId + @select_count

    select * from #t

    commit tran

    end

    END

    展开全文
  • 求一个java多线程并发访问sqlite数据库如何同步和加锁的demo啊各位大神,为什么网上的demo都没有那种把每个线程所做的操作分别都写出来的例子啊。。
  • 防止线程又是读取又是写入 网上找到的方法: 对于这样的问题,解决的办法就是keep single sqlite connection,保持单个SqliteOpenHelper实例,同时对所有数据库操作的方法添加synchronized关键字。 完美解决...

    防止多个线程又是读取又是写入

    网上找到的方法:

    对于这样的问题,解决的办法就是keep single sqlite connection,保持单个SqliteOpenHelper实例,同时对所有数据库操作的方法添加synchronized关键字。

    完美解决sqlite的 database locked 或者是 error 5: database locked 问题

     

    意思就是对保存删除或者此类数据库操作的最上层的方法加锁,这样就能防止数据库被同一时间不同地方调用了

    然后单例模式也可以解决数据库同时读写引起的错误;

    比如使用如下DCL模式

    public class XutilsHelper {
        private DbManager db;
    
        private static  XutilsHelper sInstance = null ;
    
        public static XutilsHelper getInstance(){
            if(sInstance == null){
                synchronized (XutilsHelper.class){
                    if(sInstance == null ){
                        sInstance  = new XutilsHelper();
                    }
                }
            }
            return sInstance;
        }
    
        private XutilsHelper(){};
         
        //相关操作代码省略  
        public ..............    
              
    }

    缺点是第一次加载时反映稍慢,但是能在绝大多数保证对象的唯一性;

     

    转载于:https://www.cnblogs.com/fengfenghuifei/p/6046611.html

    展开全文
  • 采用多线程实现.因为多线程可能在速度上很快点.   在页面上点击"查询"时,后台根据前台传过来的查询条件关键字,分别去不同位置的数据库里查询并抓取符合条件的前十条数据.&lt;分布在不同位置的数据库...
  • 最近调整原来的py爬虫时发现一个问题在多线程下pymongo会报一个危险/usr/lib64/python2.6/site-packages/pymongo/topology.py:75:UserWarning: MongoClient opened before fork. Create MongoClient with connect=...
  • 请问多线程数据库程序怎么保证线程安全问题是这样子:多台电脑(或一台电脑中的多个线程)分别从服务器读取数据,并将数据修改后写回数据库。但如果在写入服务器时服务器内数据和本机读取时不一致,则写入操作被拒绝。...
  • I have a main Python script which connects to a MySQL database and pulls out few records from it. Based on the result returned it starts as many threads (class instances) as many records are grabbed....
  • 在再每个线程中,将传递过来的参数 update到数据库中,会报一个错误,我想是不是线程同时操作一个,导致锁死?如下图: 其中, conn.connect()我只在程序最开始链接了一次, conn.cloese(),和cursor.close()只在程序...
  • 文章目录基础概念原因分析解决方案多线程插入解决:多线程更新解决 基础概念 幂等性 : 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。 简单来说:幂等就是一个操作,不论...
  • 基于C API的MySQL数据库多线程访问方法 标签: mysql数据库多线程apicdatabase 2012-04-23 13:30 6851人阅读 评论(0) 收藏 举报  分类: 数据库(11)  说明:如何生成线程式客户端 ...
  • delphi多线程访问数据库

    热门讨论 2008-12-05 14:36:49
    delphi如何多线程访问数据库的例子
  • 可是总是出现事务方面的异常比如 : SQLNonTransientConnectionException请问该如何解决上述异常,或者有什么好的多线程分页查询处理方案?原来问题描述不太清楚,现在添加以下代码(手敲,如果有错,请多包含)分页式...
  • 我想知道我需要做什么才能访问数据库线程安全。这是我的Entity类:@Entity@Table(name = "students")@NamedQuery(name = "Student.getAll", query = "SELECT s FROM Student s")public class Student {@Id@...
  • 在一个采用Swift2.0编写的IOS APP项目中,需要后台用蓝牙实时获取数据并...刚接触IOS开发,对多线程数据持久化理解不足,希望有经验的大牛指点一下有什么办法或者比较好的类库能线程安全的支持后台对数据库的频繁读写。
  • 多进程多线程访问数据库如何让多进程多线程访问数据库,而不会选择相同的数据,这在设计分布式程序的时候经常用到,多台机器的多个进程,每个进程都有多个线程,每个线程要从数据库里取数据来处理,要实现不能漏取...
  •  数据库如何调度这些线程呢?数据库实例有自己的调度机制,这样当需要线程调用时,它就不需要访问系统内核。它通常维护一个线程缓冲区,因此它不需要进行太的创建或销毁的操作。可以通过ma
  • 日常项目中,经常会出现一个场景,同时批量插入数据库数据,由于逻辑复杂或者其它原因,我们无法使用sql进行批量插入,这个时候我们首先想到多线程并发插入,但是如何控制事务呢 … 直接上干货 实现效果 开启多条子...
  • 串行效率低,耗时长,为了提高效率,这个时候我们首先想到多线程并发插入,但是如何控制事务呢 … 直接上干货实现效果开启多条子线程,并发插入数据库当其中一条线程出现异常,或者处理结果为非预期结果,则全部线程...
  • 如何让多进程多线程访问数据库,而不会选择相同的数据,这在设计分布式程序的时候经常用到,多台机器的多个进程,每个进程都有多个线程,每个线程要从数据库里取数据来处理,要实现不能漏取数据,也不能重复取数据,...
  • Android SQLiteAndroid 数据库操作数据库多线程操作 为了记录如何线程安全地访问你的Android数据库实例,我写下了这篇小小札记。文章中引用的项目代码请点击这里 假设你已编写了自己的SQLiteOpenHelper。 Java...
  • getDatabase和close方法执行时加的都是同一个锁,synchronized应该能够保证这两个方法各自执行时的原子性,其中一个方法正在执行时,另外一条线程想执行另外一个方法时应该会被阻塞,并且也能够保证int类型变量的...
  • 背景:Socket是iOS即时通讯的服务端Socket。消息全部通过该服务端转发。 Socket是用的EMTASS2_1。通过3条线程处理,分别是 数据包处理线程,侦听客户端连接请求线程,... 求高手指点指点,怪自己以前没学好多线程
  • 类型:数据库类大小:1.7M语言:英文 评分:6.6标签:立即下载一、在对网站整体性能进行...重点来说MySQL的基准测试如何进行,也有很种工具来供我们选择,比如mysqlslap、sysbench、Super Smack等,其中mys...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,099
精华内容 1,239
关键字:

数据库如何多线程