我正在学习如何使用SQLite,而且我在这个问题上停留了一个多星期,而且我在网络搜索中找不到答案。
问题在于我需要使用相应的行注册账单,并更新已购买产品的一些信息,如果某些查询失败,则在同一事务中进行更新。
当我尝试注册某些内容时,我获得“数据库已被锁定”异常,但我发现奇怪的是我在创建此问题时保持程序运行,当我看到它时我再次发现“继续”按钮可用,然后程序终于有效了。
所以我想知道如果没有那个例外我必须改进。
啊,这是一个Winforms应用程序,只有一个人会使用它,所以它不会出现并发问题(或者我认为是这样)。
首先,这是 connectionString (如果我需要添加内容): “数据源= D:\ De disco c \ Documents \ Visual Studio 2010 \ Projects \ Racion \ Racion \ bin \ Racion.db; Version = 3;”
在法案课程的Mapper上我有这个方法:
public static void registrarFactura(Factura f)
{
SQLiteConnection conn = null;
SQLiteTransaction trn = null;
try
{
var parametros = new List<SQLiteParameter>();
var cant = new SQLiteParameter();
cant.ParameterName = "@Cliente";
cant.Value = f.cliente;
parametros.Add(cant);
cant = new SQLiteParameter();
cant.ParameterName = "@Fecha";
cant.Value = DateTime.Now;
parametros.Add(cant);
//Here is one query. I need to know the bill's ID to register the lines and make the update.
String consulta = "Insert into Factura(Cliente, Fecha) VALUES (@Cliente, @Fecha); SELECT last_insert_rowid();";
//Open the connection
conn = ObtenerConection();
//begin transaction
using (trn = conn.BeginTransaction())
{
//Here I register the bill and obtain it's id
int codigo = Convert.ToInt32(Mapper.ejecutaScalar(consulta, CommandType.Text, parametros, conn, trn));
//Now I must register the lines of the bill
String consulta2 = "";
foreach (Linea l in f.lineas)
{
parametros = new List<SQLiteParameter>();
cant = new SQLiteParameter();
cant.ParameterName = "@NLinea";
cant.Value = l.numeroLinea;
parametros.Add(cant);
cant = new SQLiteParameter();
cant.ParameterName = "@Cantidad";
cant.Value = l.cantidad;
parametros.Add(cant);
cant = new SQLiteParameter();
cant.ParameterName = "@CodigoProd";
cant.Value = l.producto.Codigo;
parametros.Add(cant);
cant = new SQLiteParameter();
cant.ParameterName = "@PTotal";
cant.Value = l.PrecioTotal;
parametros.Add(cant);
cant = new SQLiteParameter();
cant.ParameterName = "@Codigo";
cant.Value = codigo;
parametros.Add(cant);
//The query to insert the actual line of the foreach
consulta = "Insert into Linea(IdFactura, IdLinea, IdProducto, Cantidad, Total) VALUES (" + codigo + ", @NLinea, @CodigoProd, @Cantidad, @PTotal)";
Mapper.EjecutaNonQuery(consulta, CommandType.Text, parametros, conn, null);
//Update the stock of the product
if (f.cliente == "")
{
consulta2 = "Update Producto Set Cantidad=Cantidad+@Cantidad Where IdProducto=@CodigoProd;";
}
else
{
consulta2 = "Update Producto Set Cantidad=Cantidad-@Cantidad Where IdProducto=@CodigoProd;";
}
Mapper.EjecutaNonQuery(consulta2, CommandType.Text, parametros, conn, null);
}
//The transaction concludes
trn.Commit();
}
}
catch (SqlException ex)
{
//If there is a problem
trn.Rollback();
}
finally
{
//Close the connection
CerrarConexion(conn);
}
}
在mapper类中,我有两个在前一个方法中使用的方法:
public static object ejecutaScalar(string sentencia, CommandType tipoComando, List<SQLiteParameter> parametros, SQLiteConnection con, SQLiteTransaction trn)
{
object retorno;
using (SQLiteCommand cmd = new SQLiteCommand())
{
cmd.Connection = con;
cmd.CommandText = sentencia;
cmd.CommandType = tipoComando;
cmd.Parameters.AddRange(parametros.ToArray());
if (trn != null)
cmd.Transaction = trn;
retorno = cmd.ExecuteScalar();
}
return retorno;
}
public static int EjecutaNonQuery(string sentencia, CommandType tipoComando, List<SQLiteParameter> parametros, SQLiteConnection con, SQLiteTransaction trn)
{
int afectadas = -1;
using (SQLiteCommand cmd = new SQLiteCommand())
{
cmd.Connection = con;
cmd.CommandText = sentencia;
cmd.CommandType = tipoComando;
cmd.Parameters.AddRange(parametros.ToArray());
if (trn != null)
cmd.Transaction = trn;
afectadas = cmd.ExecuteNonQuery();
}
return afectadas;
}
谢谢,对不起,如果我不能更好地解释我,英语不是我的母语,我有一些困难:P
答案 0 :(得分:0)
错误消息“数据库已锁定”表示存在一些具有活动事务的其他连接。
要确保事务不会保持活动状态,请检查所有 SQL命令和事务对象是否仅用于using
块,或以其他方式清除。此外,整个程序应该只使用一个连接对象(除非它有多个线程);你不应该每次都重新打开它(因为页面缓存丢失会使一切变慢)。