下面是一段用SQLite作为数据库的登入代码,如果密码错误3次就锁定,数据库中4个字段ID ,Tname,Tpassword,TerroTimes,其中TerroTimes记录错误次数。登入成功就重置;但是如果79行reader不关闭就无法更新TerroTimes的值,不报错,就卡在那里了。本人是新手,许多帖子都说SQLite支持并发。但这里为什么不关闭reader,新建的connection就不能更新数据……用断点跟踪发现到31 cmd.ExecuteNonQuery();就运行不了卡住了,如主线程被挂起的感觉……
求解,这是SQLite自身的原因,还是我写的代码有问题。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.Data.SQLite; 10 11 namespace 登入程序 12 { 13 public partial class Form1 : Form 14 { 15 public Form1() 16 { 17 InitializeComponent(); 18 } 19 20 private void IncErroTimes() 21 { 22 MessageBox.Show("1"); 23 string Sconn = @"Data Source=D:\C_NET\SQLite\SQListe测试\SQListeTest.db;Version=3;Password=123;"; 24 using (SQLiteConnection conn = new SQLiteConnection(Sconn)) 25 { 26 conn.Open(); 27 using (SQLiteCommand cmd = conn.CreateCommand()) 28 { 29 cmd.CommandText = "update T_User set FerroTimes=FerroTimes+1 where Fname=@name;"; 30 cmd.Parameters.Add(new SQLiteParameter("name", txtusername.Text)); 31 cmd.ExecuteNonQuery(); 32 } 33 } 34 } 35 private void ResErroTimes() 36 { 37 string Sconn = @"Data Source=D:\C_NET\SQLite\SQListe测试\SQListeTest.db;Version=3;Password=123;"; 38 using (SQLiteConnection conn = new SQLiteConnection(Sconn)) 39 { 40 conn.Open(); 41 using (SQLiteCommand cmd = conn.CreateCommand()) 42 { 43 cmd.CommandText = "update T_User set FerroTimes=0 where Fname=@name;"; 44 cmd.Parameters.Add(new SQLiteParameter("name", txtusername.Text)); 45 } 46 } 47 } 48 49 private void button1_Click(object sender, EventArgs e) 50 { 51 string Sconn = @"Data Source=D:\C_NET\SQLite\SQListe测试\SQListeTest.db;Version=3;Password=123;"; 52 using (SQLiteConnection conn = new SQLiteConnection(Sconn)) 53 { 54 conn.Open(); 55 using (SQLiteCommand cmd = conn.CreateCommand()) 56 { 57 cmd.CommandText = "select * from T_User where Fname=@name;"; 58 cmd.Parameters.Add(new SQLiteParameter("name", txtusername.Text)); 59 cmd.ExecuteNonQuery(); 60 using (SQLiteDataReader reader = cmd.ExecuteReader()) 61 { 62 if (reader.Read()) 63 { 64 if (reader.GetInt32(reader.GetOrdinal("FerroTimes")) > 3) 65 { 66 MessageBox.Show("登入失败次数太多"); 67 return; 68 } 69 //用户名存在 70 if (txtpassword.Text == reader.GetString(reader.GetOrdinal("Fpassword"))) 71 { 72 ResErroTimes(); 73 MessageBox.Show("登入成功!"); 74 } 75 else 76 { 77 78 MessageBox.Show("密码错误!"); 79 reader.Close();//如果reader不关闭IncErroTimes将无法运行 80 IncErroTimes(); 81 } 82 } 83 else 84 { 85 MessageBox.Show("输入的用户名有误!"); 86 } 87 } 88 } 89 } 90 } 91 } 92 }
ResErroTimes()这个方法少了
cmd.ExecuteNonQuery();吧。
SQLite数据库在使用的过程中经常发生的数据库异常便是数据库被锁定了(SQLITE_BUSY或者SQLITE_LOCKED)。SQLite对于并发的处理机制是允许同一个进程的多个线程同时读取一个数据库,但是任何时刻只允许一个线程/进程写入数据库。所以必须要对数据库的读写来进行控制。
额!不好意思……是有的,整理代码的时候误删了。
但是上边的代码,只有两个封装的方法是写操作,其他都是读啊。而且两个方法用了Using跳出后资源都释放掉了,不存在两个写操作冲突的问题……。
@文刀的积淀: 你读了后,再写啊。你要是都是读,就不会出现这种问题了。
@荒野的呼唤: 意思是读写操作不能并存,但是多个读操作可以同时存在。是这个意思吧!
@文刀的积淀: 是的。
这个写法:
cmd.Parameters.Add(new SQLiteParameter("name", txtusername.Text));
就有问题吧,要用@name
这样写没问题啊……关键不在这个地方……我去掉更新TerroTimes字段的两个方法后,程序完全能正常的跑起来。