文章描述:主要说明转换成SQL语句的过程。----必要信息(数据库名,表名,条件)转换成SQL语句
一些界面上数据增删改查的操作往往只需要输入一数据库名,表名,加条件就可以进行数据查询了,在这背后是怎么实现了呢,这些程序有些是使用封装的方法,有些直接输入sql语句进行操作,封装的方法最后也是将查询条件(上面输入操作)转换为SQL语句用Statement对象对应方法进行相关操作
而Statement对象获得SQL语句后怎么执行查询(这个不归statement管了),Statement这里是通过jdbc(或者其他驱动如:ODBC等)将SQL语句放入数据库,由数据库进行解释操作。这个速度较慢
preparedstatement:是java这边将原始的SQL语句进行解释,然后将中间码录入数据库,数据库直接执行,这样速度相比statement这种方式会更快!!!
我是一条分割线^_^
在android中,提供了一些方便数据操作,不需要程序员写sql语句,只需要写如关键参数+条件。后面执行过程不需要我们考虑。
如android中的SQLite操作SQLiteDatabase封装很多方法
insert(String table, String nullColumnHack, ContentValues initialValues )//Convenience method for inserting a row into the database.
简单的方法对于插入一行数据到数据库中
@param table:表名
@param nullColumnHack:要强行插入null值的列名
@param initialValues :是一个HashMap存储的键值对,里面的key代表columnName列名,value代表在该行的key值所对应列要插入的值
一般情况下nullColumnHack为null
如
ContentValues contentValues = new ContentValues(); String name="我是书的名字"; contentValues.put("bookName",name); insert("book",null,contentvalues)
上面insert语句最后会转化为SQL语句
insert into book(bookName) values("我是书的名字")
当然这个转换过程不是这样了。
StringBuilder sql = new StringBuilder();//StringBuilder一个可变的字符序列 sql.append("INSERT"); sql.append(CONFLICT_VALUES[conflictAlgorithm]); sql.append(" INTO "); sql.append(table); sql.append(‘(‘); Object[] bindArgs = null;//bindArgs存放的是value[]数组,要插入的数据 int size = (initialValues != null && initialValues.size() > 0) ? initialValues.size() : 0; if (size > 0) { bindArgs = new Object[size]; int i = 0; for (String colName : initialValues.keySet()) {//循环添加列名对应insert into table(colName1,..2,...colN)括号里面的所有列名 sql.append((i > 0) ? "," : ""); sql.append(colName); bindArgs[i++] = initialValues.get(colName);//将要插入的数据全部复制到bindArgs数组中 } sql.append(‘)‘); sql.append(" VALUES ("); for (i = 0; i < size; i++) { sql.append((i > 0) ? ",?" : "?"); } } else { sql.append(nullColumnHack + ") VALUES (NULL"); } sql.append(‘)‘);
上面形成sql语句是insert into book(bookName) values(?),还有生成一个数据数组bindArgs。
如果数据initialValues 的值为null,则会执行insert into book(nullColumnHack) values(NULL)强行将列的值设为null
----到最后,会将statement对象和bindArgs数据进行绑定最后给数据库解释执行
感觉其它封装的数据库类原理和这个都是相似的吧
总结:
执行数据库操作的步奏:
1构造Statement对象
2statement来执行某种(增删改查etc.)操作
3通过session调用到连接池中某个connection的execute相关方法。
4在connection中重新构建PreparedStatement(其实该对象才真正指向sqlite中的stmt),绑定数据和PreparedStament对象,调用Native方法底层JNI
PS:
android中sqlite的内部流程
打开数据库操作Android SQLite 打开、操作分析
SQLiteDatabase.openDataBase SQLiteDatabase.open SQLiteDatabase.openInner SQLiteConnectionPool.open SQLiteConnectionPool.openConnectionLocked打开连接池 SQLiteConnection.open nativeOpen最后调用底层打开
执行数据库操作
SQLiteStatement statement = new SQLiteStatement()时,使得该SQLiteDatabase的某个connection拥有对应的PreparedStatement.
statement.execute()时,会在SQLiteDatabase的多个connection中找到含有对应PreparedStatement的connection来使用.
假如该connection恰巧被其他线程使用了,得到的是另一个connection,其会重新acquirePreparedStatement。
DatabaseUtils.getSqlStatementType(mSql)这个mSql语句为select
db.getThreadSession().prepare//SQLiteSeesion SQLiteConnection.prepare SQLiteConnection.acquirePreparedStatement(sql) ----SQLiteConnection中操作 statement=SQLiteConnection.mPreparedStatementCache.get(sql) if(statement!=null) { if (!statement.mInUse) { // 并且不在使用中 return statement; // 返回该statement } skipCache = true; // 如果已在使用 另备一份并不再缓存 } final int statementPtr = nativePrepareStatement(mConnectionPtr, sql); //native try { final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr); final int type = DatabaseUtils.getSqlStatementType(sql); final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr); statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly); // 从池中获取一个statement,并将其从池中移除 if (!skipCache && isCacheable(type)) { mPreparedStatementCache.put(sql, statement); // 将statement放入缓存中 statement.mInCache = true; } statement.mInUse = true; return statement; ------获得PreparedStatement
SQLiteOpenHelper保证一个实例里只有一个SQLiteDatabase
SQLiteDatabase.openDatabase的过程是构建SQLiteDatabase对象的过程,实质是构建SQLiteDatabase的成员变量SQLiteConnectionPool的过程,该过程是一个获取primaryConnection的过程。
每个线程有自己的SQLiteSession且只有一个,每个SQLiteSession在某一时刻最多只有一个SQLiteConnection(需要时从连接池获取,用完返还),保证了一个线程在某一时刻只有一个SQLiteConnection连接到某一SQLiteDatabase。事务同样通过Session来实现,故线程之间的事务是独立的
SQLiteConnectionPool掌管某个SQLiteDatabase的连接池。确保PrimaryConnection只有一个,如果空闲则将其返回,如果正被其他session使用则返回空,如果没有则新建。对于非PrimaryConnection,将会在连接池中优先选取stmt相同的,如果没有相同的获取池中最后一个,如果池子已经空了(此时多个线程同时用着多个连接),新建一个非主连接。
不知道有没有错,先记着两片不同文章,