[转载]Android学习笔记(六)SQLite

mikel阅读(972)

[转载]Android学习笔记(六)SQLite – Libo@Deng – 博客园.

一、废话

今天感冒了!… …(以下省略500字)

二、正文

1、  SQLite是个啥?

SQLite是一个极轻量型的数据库。它在提供了和大型数据库相当的功能,还具有轻便、跨平台等优点,SQLite使用非常方便,并不需要我们 像常规数据库(SQLServer,Mysql等)那样进行安装,在Android的JDK中,其实是已经包含了SQLite这个数据库的核心。当然我们 必须要强调一点,SQLite并不是只针对Android的,其实它还可以用在别的很多地方。

2、  在Android系统中如何使用SQLite数据库?

要在Android系统中使用SQLite数据库,其实是一件非常轻松的事情,只要继承来自android.database.sqlite包中的SQLiteOpenHelper类,并重写其中的几个重要方法后,你就可以对数据库进行相关的操作了。

 1 public class MyDatabaseHelper extends SQLiteOpenHelper {
 2  
 3     private static final String DB_NAME = "test_db"; //数据库名称
 4     private static final int VERSION = 1; //数据库版本
 5      
 6     public MyDatabaseHelper(Context context) {
 7         super(context, DB_NAME, null, VERSION);
 8         // TODO Auto-generated constructor stub
 9     }
10  
11     @Override
12     public void onCreate(SQLiteDatabase db) {
13         String sql = "create table user(username varchar(25) not null , password varchar(60) not null );";          
14         db.execSQL(sql);
15     }
16  
17     @Override
18     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
19         // TODO Auto-generated method stub
20  
21     }
22  
23 }

还是先来看看SQLiteOpenHelper这个类吧。“A helper class to manage database creation and version management.”官方的一个帮助文档这样描述这个类,也就是说,这个类主要的作用是用来创建数据库和对数据库进行版本更新的。

这个类中必须重写的两个方法分别为:onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)。

  • onCreate(SQLiteDatabase db):用于创建数据库db中的表,而不是创建db数据库实例。这个方法并不需要我们自己去调用,当数据库第一次被创建时,这个方法会自动被调用。那么数 据库真正的创建是在什么时候呢?当我们调用getReadableDatabase()/getWritableDatabase()方法时,数据库会被 真实的创建。
  • onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):这个方法用来对数据库进行更新操作,你可以在这个方法中定义你自己的一些操作。这个方法也不需要我们主动去调用,当 SQLiteOpenHelper类的最后一个参数比原值大的时候,这个方法会自动被调用。调用的时刻同onCreate()方法。

另外在SQLiteOpenHelper类中,还有两个方法也非常重要:getReadableDatabase(),getWritableDatabase()。

  • getReadableDatabase():返回一个只读的数据库实例,在访问数据库中数据但同时又不需要对其进行数据修改时(select操作)可以使用这个方法。
  • getWritableDatabase():返回一个可读写的数据库实例,当需要对数据库进行数据修改时,应该调用这个方法。记住在使用完成后,一定是要使用close()方法来释放内存,否则会造成内存泄露。

3、  在Android系统中如何对SQLite数据库进行常规操作?

  • (Cursor) query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)——查询操作,返回一个游标
    • table——表名;
    • columns——列名集合
    • selection——在where语句中的表达式,如id=?
    • selectionArgs——在where表达式中传入的参数,也就是上面“?”所占据的值
    • groupBy\having\orderby\limit——这些参数如果各位不清楚,请google下SQL语句基础
       1public Cursor Query(String table, String[] filed, long rowId)
       2throws SQLException {
       3
       4         Cursor mCursor = _db.query(true, table, filed, "ID=?" + rowId, null,null, null, null, null);
       5if (mCursor != null) {
       6             mCursor.moveToFirst();
       7         }
       8return mCursor;
       9     }
      10
      11public Cursor Query(String table) {
      12         Cursor mCursor = _db.query(true, table, new String[] { "*" }, null,null, null, null, null, null);
      13if (mCursor != null) {
      14             mCursor.moveToFirst();
      15         }
      16return mCursor;
      17     }
  • (int) update(String table, ContentValues values, String whereClause, String[] whereArgs)——进行更新操作
    • table——表名
    • values——ContentValues类型,其实就是键值对,键代表需要修改的列名,值代表对应的新值
    • whereClause——where语句中的表达式,可以直接组成一个完整的表达式如:id=1,此时whereArgs传入null,如果id=?,那么whereArgs和query(…)的selectionArgs一样。
    • whereArgs——在where表达式中传入的参数
       1 public boolean Update(String table, String[] fieldName,
       2             String[] fieldValue, long rowID) throws SQLException {
       3         ContentValues cv = new ContentValues();
       4 for (int i = 0; i < fieldName.length; i++) {
       5             cv.put(fieldName[i], fieldValue[i]);
       6         }
       7 if (_db.update(table, cv, "ID=" + rowID, null) > 0) {
       8 return true;
       9         }
      10 return false;
      11     }
  • (long) insert(String table,String nullColumnHack,ContentValues values)——进行插入操作
    • table——表名
    • nullcolumnHack——当插入空值的时候有用
    • values——键值对,键代表需要修改的列名,值代表对应的新值
       1 public boolean Insert(String table, String[] fieldName, String[] fieldValue) throws SQLException {
       2         ContentValues cv = new ContentValues();
       3 for (int i = 0; i < fieldName.length; i++) {
       4             cv.put(fieldName[i], fieldValue[i]);
       5         }
       6 if (_db.insert(table, null, cv) > 0) {
       7 return true;
       8         }
       9 return false;
      10     }
  • (int) delete(String table,String whereClause,String[] whereArgs)——进行删除操作
    • table——表名
    • whereClause/whereArgs——同update()方法
      1 public boolean Delete(String table, long rowID) throws SQLException {
      2 if (_db.delete(table, "ID=?", new String[] { rowID + "" }) > 0)
      3 return true;
      4 return false;
      5     }
  • (void) execSQL(String sql)——执行sql语句
    • 执行非select操作的语句,灵活性强。

在上面的方法中,有看不懂的地方,请看Demo源码。

三、总结

SQLite作为一个轻型数据库,在Android中可以用来存储用户数据,如短信、联系人等信息。在Android中使用SQLite是非常灵活的,所以不一定非要按照某一种特定的方式来操作数据库。下一篇笔记中将说说ContentProvider类。

[转载]Android开发教程 --- 数据存储(2) SQLite

mikel阅读(1079)

[转载]Android开发教程 — 数据存储(2) SQLite – Jason_CC – 博客园.

Hi,大家好!

今天我们主要来讲讲SQLite在Android中的使用。

轻松下:

写字楼里写字间,写字间里程序员;
程序人员写程序,又拿程序换酒钱。
酒醒只在网上坐,酒醉还来网下眠;
酒醉酒醒日复日,网上网下年复年。
但愿老死电脑间,不愿鞠躬老板前;
奔驰宝马贵者趣,公交自行程序员。
别人笑我忒疯癫,我笑自己命太贱;
不见满街漂亮妹,哪个归得程序员。  🙂 哎…

SQLite简介

大部分应用程序都要操作数据,,Android应用程序也不例外,本地数据应该存储在什么地方?Android使用开源的、与操作系统无关的SQL数据库 –大名鼎鼎的SQLite。SQLite是一款轻量级数据库,它的设计目的是嵌入式,而且它占用的资源非常少,在嵌入式设备中,只需要几百KB,很多大型公司所开发的产品都有它的存在。

轻量级
使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸相当小。

独立性
SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。

隔离性
SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。

跨平台
SQLite 目前支持大部分操作系统,不止电脑操作系统更在众多的手机系统也是能够运行,比如:Android。

多语言接口
SQLite 数据库支持多语言编程接口。

安全性
SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。

SQLite虽然很小巧,但是支持的SQL语句不会逊色于其他开源数据库,它支持的SQL包括:

1

Sqlite基本数据类型有:

VARCHAR 字符型

NVARCHAR(15)可变字符型,

TEXT 文本型,

INTEGER 整型,

FLOAT 浮点型,

BOOLEAN布尔型,

CLOB字符大对象,

BLOB二进制大对象,

TIMESTAMP日期型,

NUMERIC(10,5) 数值型

VARYING CHARACTER (24),

NATIONAL VARYING CHARACTER(16)

Sqlite也提供了JDBC驱动程序

Class.forName(“org.sqlite.JDBC”);

Connection conn = DriverManager.getConnection(“jdbc:sqlite:filename”);

//filename为你的SQLite数据名称

使用SQLiteOpenHelper操作数据库

getReadableDatabase()获得可读的SQLiteDatabase

getWritableDatabase() 获得可写的SQLiteDatabase

onCreate(SQLiteDatabase)

onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

操作数据库

1. 封装一个SQLite的操作类,并且在此使用继承SQLiteOpenHelper的方式实现

SQLiteOpenHelper
SQliteOpenHelper是一个抽象类,来管理数据库的创建和版本的管理。要使用它必须实现它的

onCreate(SQLiteDatabase),

onUpgrade(SQLiteDatabase, int, int)方法
onCreate:当数据库第一次被建立的时候被执行,例如创建表,初始化数据等。
onUpgrade:当数据库需要被更新的时候执行,例如删除久表,创建新表。

2. 实现SQLiteOpenHelper类的构造函数及抽象方法.

package TSD.Jason.DB;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;

public class DBHelp extends SQLiteOpenHelper {

    private final static String DATABASE_NAME="StudentDB"; //数据库名称
    private final static int DATABASE_VERSION=1; //数据库默认版本
    private final static String TABLE_NAME="StudentInfo"; //数据表名称
    public final static String S_ID="sid";  // 列名
    public final static String S_NAME="sName"; 
    public final static String S_SEX="sSex"; 
    public final static String S_AGE="sAge";
    public final static String S_ADDRESS="sAddress"; 
    
    /**SQLiteOpenHelper类的构造函数  (注意: 必须实现的构造函数)
     * 
     * 此构造函数用来 创建库和表 (第一次执行时,如果没有库、表,将创建库、表,以后将不再创建)
     * @param context  上下文对象
     * @param name 数据库名称
     * @param factory 创建Cursor的工厂类。参数是为了可以自定义Cursor创建
     * @param version 数据库版本号
     */
    public DBHelp(Context context, String name, CursorFactory factory,
            int version) {
        super(context, name, factory, version);
        
    }
    
    /**操作数据时,(增删改查)
     * 
     * @param context  上下文对象
     * @param name 数据库名称
     * @param factory 创建Cursor的工厂类。参数是为了可以自定义Cursor创建
     * @param version 数据库版本号
     */
    public DBHelp(Context context) {
        this(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    
    /**需要根据版本号来实现修改
     * 
     *此构造函数用来 修改库和表 (修改现有的库、表)
     * @param context  上下文对象
     * @param name 数据库名称
     * @param factory 创建Cursor的工厂类。参数是为了可以自定义Cursor创建
     * @param version 数据库版本号
     */
    public DBHelp(Context context ,int version) {
        this(context,DATABASE_NAME,null,version);
    }
    
    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub
        System.out.println("当第一次运行或者修改数据库时,将会自动执行");
        
        String createTableSQL = "create table " + TABLE_NAME + "("
                                +S_ID         + " integer  primary key autoincrement,"
                                +S_NAME     + " nvarchar(10),"
                                +S_SEX         + " nvarchar(2),"
                                +S_AGE         + " int,"
                                +S_ADDRESS     + " nvarchar(50)"
                                +")";
        db.execSQL(createTableSQL); // 执行SQL 需要使用execSQL()
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        System.out.println("-------------------------调用了一个修改库函数");
        
    }
    
    @Override
    public void onOpen(SQLiteDatabase db) {
        // TODO Auto-generated method stub
        super.onOpen(db);
        System.out.println("当数据库打开时,执行");
    }
    
    

}

创建数据库

DBHelp dbHelp = new DBHelp(SQLiteActivity.this);
                //当获得了SQLiteDatabase对象,会自动检测是否第一次创建了库,表,如果没有将执行DBHelp类中的onCreate函数
                SQLiteDatabase db = dbHelp.getReadableDatabase();
                Toast.makeText(SQLiteActivity.this, "创建成功", Toast.LENGTH_SHORT).show();


getWritableDatabase() 如果需要操作(增删改)数据库时,使用

getReadableDatabase()查询数据

删除及重命名数据库

2

在adb下查看数据库

3

1通过 ls 命令查询目录结构

2通过cd 文件夹名称 进入对应的文件夹中

3需要进入2次data文件夹

4进入自己创建项目的包下

5进入databases

6通过 sqlite3 StudentDB 进入数据库

在sqlite>提示符下输入

.help 这个命令让我们看到许多命令

.tables 查看所有表

通过.tables 命令,可以查询此数据库下所有表名

查询语句和SQLServer中一样,每一句Sql语句结束都需要分号;

添加数据

btn5.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                
                DBHelp dbHelp = new DBHelp(SQLiteActivity.this);
                SQLiteDatabase db = dbHelp.getWritableDatabase();
                ContentValues contentValues = new ContentValues();
                contentValues.put("sName", txtName.getText().toString());
                contentValues.put("sSex", "男");
                if(dbHelp.InsertData(db, contentValues))
                    Toast.makeText(SQLiteActivity.this, "添加成功", Toast.LENGTH_SHORT).show();
                else
                    Toast.makeText(SQLiteActivity.this, "添加失败", Toast.LENGTH_SHORT).show();
            }
        });

修改数据

btn6.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                
                DBHelp dbHelp = new DBHelp(SQLiteActivity.this);
                SQLiteDatabase db = dbHelp.getWritableDatabase();
                ContentValues contentValues = new ContentValues();
                contentValues.put("sName", txtsName.getText().toString());
                String whereClause = "sid=?"; //要修改数据的条件 值用?占位符
                String[] whereArgs = new String[]{txtsID.getText().toString()};
                if(dbHelp.UpdateData(db, contentValues, whereClause, whereArgs))
                    Toast.makeText(SQLiteActivity.this, "修改成功", Toast.LENGTH_SHORT).show();
                else
                    Toast.makeText(SQLiteActivity.this, "修改失败", Toast.LENGTH_SHORT).show();
            }
        });

删除数据

    btn7.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                
                DBHelp dbHelp = new DBHelp(SQLiteActivity.this);
                SQLiteDatabase db = dbHelp.getWritableDatabase();
                String whereClause = "sid=?"; //要删除数据的条件 值用?占位符
                String[] whereArgs = new String[]{txtID.getText().toString()};
                if(dbHelp.DeleteData(db, whereClause, whereArgs))
                    Toast.makeText(SQLiteActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
                else
                    Toast.makeText(SQLiteActivity.this, "删除失败", Toast.LENGTH_SHORT).show();
            }
        });

查询数据

rawQuery()

rawQuery() 是最简单的解决方法。例如:

Cursor c=db.rawQuery(
“SELECT * FROM Student WHERE sid=1 AND sname=‘zhangsan'”, null);

query()

都会返回一个 Cursor,这是 Android 的 SQLite 数据库游标

操作游标

通过使用 getCount() 方法得到结果集中有多少记录;
通过 moveToFirst(), moveToNext(), 和 isAfterLast() 方法遍历所有记录;
通过 getColumnNames() 得到字段名;
通过 getColumnIndex() 转换成字段号;
通过 getString(),getInt() 等方法得到给定字段当前记录的值;
通过 requery() 方法重新执行查询得到游标;
通过 close() 方法释放游标资源;
SimpleCursorAdapter
SimpleCursorAdapter
可使用此类来绑定ListView

SimpleCursorAdapter simple = new SimpleCursorAdapter(SQLiteActivity.this, android.R.layout.simple_list_item_1, cur, new String[]{“sName”,”sSex”}, new int[]{android.R.id.text1,android.R.id.text2});

studentList.setAdapter(simple);

注意: 使用此类绑定数据,,必须注意sqlite的主键命名。由于simpleCursorAdapter的方法只识别_id,所以,当你用到sqlite的 simpleCursorAdapter时,必须把数据表的主键命名为_id。否则就会出现 java.lang.IllegalArgumentException: column ‘_id’ does not exist 错误。

查询数据
public void BinderData(){
        DBHelp dbHelp = new DBHelp(SQLiteActivity.this);
        SQLiteDatabase db = dbHelp.getReadableDatabase();
        /*参数
         * table 表名
         * columns 要查询的列名数组,所有列用 null
         * selection 要查询的条件 没有用null
         * selectionArgs 要查询的条件对应的值 没有用null
         * groupBy 分组 没有用null
         * having 分组后再次筛选   没有用null
         * orderBy 排序  没有用null
         * */
        Cursor cur = db.query("StudentInfo", null, null, null, null, null, null);
        //Cursor cur = db.rawQuery("select * from StudentInfo", null);
        
        //由于本例中使用的主键名不是_id 所以不能直接使用SimpleCursorAdapter 原因在PPT中已经做了说明
        //SimpleCursorAdapter simple = new SimpleCursorAdapter(SQLiteActivity.this, android.R.layout.simple_list_item_1, cur, new String[]{"sName","sSex"}, new int[]{android.R.id.text1,android.R.id.text2});
        //studentList.setAdapter(simple);
        ArrayList<HashMap<String, Object>> students = new ArrayList<HashMap<String,Object>>();
        HashMap<String, Object> hs ;
        for (cur.moveToFirst();!cur.isAfterLast();cur.moveToNext()) {
            System.out.println(cur.getInt(cur.getColumnIndex("sid"))+"aaaaaaaaa");
            hs = new HashMap<String, Object>();
            hs.put("sID", cur.getInt(cur.getColumnIndex("sid")));
            hs.put("sName", cur.getString(cur.getColumnIndex("sName")));
            hs.put("sSex", cur.getString(cur.getColumnIndex("sSex")));
            students.add(hs);
        }
        SimpleAdapter sim = new SimpleAdapter(SQLiteActivity.this, students, android.R.layout.simple_list_item_1, new String[]{"sName","sSex"}, new int[]{android.R.id.text1,android.R.id.text2});
        studentList.setAdapter(sim);
    }


代码已上传北京天圣达网站,欢迎大家下载

[转载]Eclipse中Android项目引用其他项目时链接源码的方法

mikel阅读(914)

[转载]Eclipse中Android项目引用其他项目时链接源码的方法 – 斯克迪亚 – 博客园.

参照前一篇文章《Eclipse中Android公共库的正确建立及调用方法》,以前只要在Android库中添加了引用,就能自动在项目中引入源码:

image

但是更新了新版SDK及ADT插件之后,源码不会被自动引用进来,在当前项目中只能以只读方式访问经编译后的源码:

image

那么如何手动引入源码呢?

你需要在项目上右键点选属性菜单,然后左栏选择“Java Build Path”,在右侧“Source”标签中点击“Link Source…”按钮:

SNAGHTML3c8397a

单击“Browse…”按钮:

SNAGHTML3c99c42

浏览并选取引用项目的src目录:

SNAGHTML3ca8a58

确定后修改一下文件夹显示名称:

image

这样源码就被正确链接引用,可以随时跳转后修改了:

image

另 需注意的是,这种方法在编译时会引发臭名昭著傻逼至极的“Conversion to Dalvik format failed with error 1”错误,无法通过编译,这时只需从项目中删除该链接源码目录,即可通过编译,但你在编译之后还得按上述方法添加回来以方便编码,不得不称赞 Android SDK研发小组真乃绝世脑瘫组合,每次升级SDK都会带来大把大把诡异的错误给开发者。

[转载]android应用开发全程实录-实现甩动拨打和挂断电话

mikel阅读(840)

[转载]android应用开发全程实录-实现甩动拨打和挂断电话 – noTice501 – 博客园.

今天继续给大家带来《Android应用开发全程实录》中的章节,这部分是讲传感器中的一个实例。

通过上面的例子我们学会了如何获得某种类型的传感器,下面通过一个实例来学习如何使用某一个类型的传感器。我们以加速传感器为例,来实现这样一个功能:摇动手机便自动拨打某亲情号码,并实现再次摇动则挂机的功能。

工程目录:EX_12_03

第一步,UI布局main.xml的代码如下,其运行效果如图12-10所示。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <TextView  android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="当前状态:就绪"
    android:id="@+id/state"
    android:textColor="#ff0000" />
    <Button android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/call"
    android:text="打电话(10086)"/>    
    <Button android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/stop"
    android:text="挂机"/>  
    </LinearLayout>

第二步,挂电话需要用到系统的Itelephony类的支持,由于Google从Android 2.1 SDK版本后,屏蔽了com.android.internal.telephony. Itelephony类,因此,需要从Android源码下载,找到该类并导入到工程目录下,记得包名一致。

第三步,Activity类ShakeSensorActivity的实现。该类实现SensorListener接口,添加 加速度侦听事件,通过判断设备X、Y、Z方向的总晃动值来判断是否启动打电话和挂机操作。以拨打10086测试为例,当设备总晃动值大于100作为一个测 试判断点,如果当前没有在通话界面,就通过Intent启动拨打电话,否则就挂机操作。设备摇动时,启动电话、挂机的界面状态如图图12-11、图 12-12所示。

▲图12-10  软件运行效果图            12-11 电话启动界面 12-12 摇动设备挂机时的状态界面

下面就来看看代码:

public class ShakeSensorActivity extends Activity implements SensorListener {
    private float lastX;
    private float lastY;
    private float lastZ;
    private View mainView;
    private long currTime;
    private long lastTime;
    private long duration;// 持续时间 
    private float currShake;
    private float totalShake;
    private ITelephony iTelephony;
    private boolean isCalling = false;
    SensorManager sm = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainView = LinearLayout.inflate(this, R.layout.main, null);
        setContentView(mainView);
        ((Button) mainView.findViewById(R.id.call)).setOnClickListener(new     
OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // 打电话
                        callPhoneNumber10086();
                    }
                });
        ((Button) mainView.findViewById(R.id.stop)).setOnClickListener(new OnClick-         Listener() {
                    @Override
                    public void onClick(View v) {
                        // 挂机
                        closePhone();
                    }
                });
        // 获取传感器管理器
        sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        // 注册加速度传感器 
        sm.registerListener(this, 
SensorManager.SENSOR_ACCELEROMETER,SensorManager.         SENSOR_DELAY_NORMAL);

    }
    @Override
    public void finish() {
        // TODO Auto-generated method stub
        super.finish();
        sm.unregisterListener(this);// 注销侦听

    }
    @Override
    public void onAccuracyChanged(int sensor, int accuracy) {
        // 精度改变,该方法实质上不做任何操作,它只在每次调用时,添加一个日志项
    }
    @Override
    public void onSensorChanged(int sensor, float[] values) {
        float x = values[0];
        float y = values[1];
        float z = values[2];
        currTime = System.currentTimeMillis();
        if (lastX == 0 && lastY == 0 && lastZ == 0) {
            // 第一次shake
            lastTime = currTime;
        }
        if (currTime - lastTime > 200) {// 200毫秒检测一次
            duration = currTime - lastTime;
            currShake = (Math.abs(x - lastX) + Math.abs(y - lastY) + Math.abs(z    - lastZ))/ duration * 200;
        }
        totalShake = totalShake + currShake;
        if (totalShake > 100) {
            totalShake = 0;// 重置为0,重新累计计数
            lastX = 0;
            lastY = 0;
            lastZ = 0;
            lastTime = 0;
            currTime = 0;
            if (!isCalling) {
                callPhoneNumber10086();
                ((TextView) mainView.findViewById(R.id.state)).setText("当前状态:                通话中...");
            } else {
                closePhone();
                ((TextView) mainView.findViewById(R.id.state)).setText("当前状态:通话结束...");
            }
        }
        lastX = x;
        lastY = y;
        lastZ = z;
        lastTime = currTime;
    }

    /**
     * tell 10086打开通话界面
     */
    private synchronized void callPhoneNumber10086() {
        isCalling = true;
        Intent myIntentDial = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + 10086));
        startActivity(myIntentDial);
    }

    /**
     * 结束通话
     */
    private synchronized void closePhone() {
        try {
            getTelephony();
            iTelephony.endCall();
            isCalling = false;
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * 初始电话 实例
     */
    public void getTelephony() {

        TelephonyManager telMgr = (TelephonyManager) 
this.getSystemService(Service.         TELEPHONY_SERVICE);
        Class<TelephonyManager> c = TelephonyManager.class;
        Method getITelephonyMethod = null;
        try {
            getITelephonyMethod = c.getDeclaredMethod("getITelephony",(Class[]) null);
            getITelephonyMethod.setAccessible(true);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
            iTelephony = (ITelephony) 
getITelephonyMethod.invoke(telMgr,(Object[])null);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

通过getTelephony()方法,初始一个iTelephony实例,方便调用,目前只用到了挂机关闭通话,打电话也可以通过iTelephony.dial(“10086”)直接拨打。这样就轻松实现了用传感器实现甩动打、挂电话功能。

[转载]T-SQL查询高级--理解SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤

mikel阅读(1230)

[转载]T-SQL查询高级–理解SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤 – CareySon – 博客园.

写在前面:这是第一篇T-SQL查询高级系列文章.但是T-SQL查询进阶系列还远远没有写完。这个主题放到高级我想是因为这个主题需要一些进阶的知识作为基础..如果文章中有错误的地方请不吝指正.本篇文章的内容需要索引的知识作为基础。

简介


在SQL SERVER中,非聚集索引其实可以看作是一个含有聚集索引的表.但相比实际的表而言.非聚集索引中所存储的表的列数要窄很多,因为非聚集索引仅仅包含原表中非聚集索引的列和指向实际物理表的指针。

1

并且,对于非聚集索引表来说,其中所存放的列是按照聚集索引来进行存放的.所以查找速度要快了很多。但是对于性能的榨取来说,SQL SERVER总是竭尽所能,假如仅仅是通过索引就可以在B树的叶子节点获取所需数据,而不再用通过叶子节点上的指针去查找实际的物理表,那性能的提升将会 更胜一筹.

下面我们来看下实现这一点的几种方式.

非聚集索引的覆盖


正如前面简介所说。非聚集索引其实可以看作一个聚集索引表.当这个非聚集索引中包含了查询所需要的所有信息时,则查询不再需要去查询基本表,而仅仅是从非聚集索引就能得到数据:

2

下面来看非聚集索引如何覆盖的:

在adventureWorks的SalesOrderHeader表中,现在只有CustomerID列有非聚集索引,而BillToAddressID没有索引,我们的查询计划会是这样:

3

查询会根据CustomerID列上的非聚集索引找到相应的指针后,去基本表上查找数据.从执行计划可以想象,这个效率并不快。

下面我们来看覆盖索引,通过在CustomerID和BillToAddressID上建立非聚集索引,我们覆盖到了上面查询语句的所有数据:

4

通过覆盖索引,可以看到执行计划简单到不能再简单,直接从非聚集索引的叶子节点提取到数据,无需再扫描基本表!

这个性能的提升可以从IO统计看出来,下面我们来看有覆盖索引和没有覆盖索引的IO对比:

5

索引的覆盖不仅仅带来的是效率的提升,还有并发的提升,因为减少了对基本表的依赖,所以提升了并发,从而减少了死锁!

理解INCLUDE的魔力

上面的索引覆盖所带来的效率提升就像魔术一样,但别着急,正如我通篇强调的一样,everything has price.如果一个索引包含了太多的键的话,也会带来很多副作用。INCLUDE的作用使得非聚集索引中可以包含更多的列,但不作为“键”使用。

比如:假设我们上面的那个查询需要增加一列,则原来建立的索引无法进行覆盖,从而还需要查找基本表:

6

但是如果要包含SubTotal这个总金额,则索引显得太宽,因为我们的业务很少根据订单价格作为查询条件,则使用INCLUDE建立索引:

8

理解INCLUDE包含的列和索引建立的列可以这样理解,把上述建立的含有INCLUDE的非聚集索引想像成:

7

使用INCLUDE可以减少叶子“键”的大小!

非聚集索引的交叉


非聚集索引的交叉看以看作是覆盖索引的扩展!

由于很多原因,比如:

  • 在生产环境中,我们往往不能像上面建立覆盖索引那样随意改动现有索引,这可能导致的结果是你会更频繁的被客户打电话“关照”
  • 现有的非聚集索引已经很“宽”,你如果继续拓宽则增改查带来的性能下降的成本会高过提高查询带来的好处

这时候,你可以通过额外建立索引。正如我前面提到的,非聚集索引的本质是表,通过额外建立表使得几个非聚集索引之间进行像表一样的Join,从而使非聚集索引之间可以进行Join来在不访问基本表的情况下给查询优化器提供所需要的数据:

比如还是上面的那个例子.我们需要查取SalesOrderHeader表,通过BillToAddressID,CustomerID作为选择条件,可以通过建立两个索引进行覆盖,下面我们来看执行计划:

9

非聚集索引的连接


非聚集索引的连接实际上是非聚集索引的交叉的一种特例。使得多个非聚集索引交叉后可以覆盖所要查询的数据,从而使得从减少查询基本表变成了完全不用查询基本表:

比如还是上面那两个索引,这时我只查询非聚集索引中包含的数据,则完全不再需要查询基本表:

10

看起来这样的查询意义不大?但当你把查询条件变为<号时呢?或者给定范围时。还是有一定实际意义的。

非聚集索引的过滤


很多时候,我们并不需要将基本表中索引列的所有数据全部索引,比如说含有NULL的值不希望被索引,或者根据具体的业务场景,有一些数据我们不想索引。这样可以:

  • 减少索引的大小
  • 索引减少了,从而使得对索引的查询得到了加速
  • 小索引对于增删改的维护性能会更高

比如说,如下语句:

11

我们为其建立聚集索引后:

12

这时我们为其加上过滤条件,形成过滤索引:

13

由上面我们可以看出,使用过滤索引的场景要和具体的业务场景相关,对于为大量相同的查询条件建立过滤索引使得性能进一步提升

总结


本文从介绍了SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤。对于我们每一点从SQL SERVER榨取的性能的提升往往会伴随着另一方面的牺牲。作为数据库的开发人员或者管理人员来说,以全面的知识来做好权衡将会是非常重要.系统的学习数 据库的知识不但能大量减少逻辑读的数据,也能减少客户打电话”关照”的次数:-)

[转载]ASP.NET MVC 3 开发的20个秘诀(十七)[20 Recipes for Programming MVC 3]:卷帘式分页加载

mikel阅读(1288)

[转载][翻译]ASP.NET MVC 3 开发的20个秘诀(十七)[20 Recipes for Programming MVC 3]:卷帘式分页加载 – O2DS – 博客园.

议题

现在很多网站都与数据库进行交互。如果网站流量很大,使用SQL来检索数据会带来非常大的压力。更重要的是,用户希望在点击链接之后15秒 内得到响应的内容,而在页面加载的时,显示之外滚动条下面的内容可能多数内容都是不必要的(滚动条之外没显示的部分)。为了解决这个问题,采取内容“需求 点播”方式加载。页面首先会加载足够的内容,当用户在阅读并向下滚动的时候,页面会在不影响用户阅读体验的情况下继续加载更多的内容。

解决方案

当用户开始滚动网站内容时,使用JQuery将前期加载的内容具体数值传回异步控制器,然后按需加载相关的内容。

讨论

异步控制器可能是MVC程序集中迄今为止被利用最少的或最不为人所知的控制器,当然也有可能是不知道怎么用它。以下内容是摘抄自MSDN网站的介绍信息:

在 可能出现线程不足的应用程序中,您可以配置通过异步方式处理操作。异步请求与同步请求所需的处理时间相同。例如,如果某个请求生成一个需要两秒钟来完成的 网络调用,则该请求无论是同步执行还是异步执行都需要两秒钟。但是,在异步调用的过程中,服务器在等待第一个请求完成的过程中不会阻塞对其他请求的响应。 因此,当有许多请求调用长时间运行的操作时,异步请求可以防止出现请求排队的情况。

在这个示例中,使用异步请求将是个完美的解决方案,当新用户在发起更为重要的请求时,它将会自动释放IIS资源,因为其中用户的大多数“需求点播”是不太重要的,因为大多数人甚至不会注意到正在加载的额外的内容。

在大多数社交网站中,用户的批注信息更多可能包含的是活动信息。在以前的秘诀中,实现了为书记添加评论的功能。在这个例子中,将会修改页面,列出最近的评论。当用户为了查看更多的评论,他们就会开始滚动,一旦用户开始滚动页面,就发起Ajax请求,请求异步控制器获取剩余部分评论。

首先,修改Home/Index视图,使其显示最近的评论信息。提供书籍最近的相关评论并显示查看书籍基本资料的相关链接。创建新的控制器用来显示评论,这个视图将会调用render方法来显示剩下的信息。

@model IEnumerable<MvcApplication4.Models.BookComment>
@{
    ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit
    <a href="http://asp.net/mvc"
    title="ASP.NET MVC Website">
    http://asp.net/mvc </a>.
</p>
<script type="text/javascript">
    var lastY = 0;
    var currentY = 0;
    var page = 1;
    var maxPages = @ViewBag.maxPages;
    $(window).scroll(function () {
        if (page < maxPages) {
            currentY = $(window).scrollTop();
            if (currentY - lastY > 200 * (page - 1)) {
                lastY = currentY;
                page++;
                $.get('CommentFeed/Comments?page=' + page,
                    function(data) {
                        $('#comments').append(data);
                });
            }
        }
    });
</script>
<div id="comments">
    <h2>Recent Comments</h2>
    @Html.Partial("../CommentFeed/Comments", Model)

</div>

在上面示例代码中,当浏览器窗体滚动,JavaScript代码就开始执行。在这段代码中定义了一些JavaScript全局变量,保持追踪当前滚动条“Y”坐标的位置,最后“Y”坐标的位置和当前被检索到的页面位置。当窗口的ScrollTop减去“Y”坐标最后的位置大于某个具体数字,则通过Ajax请求书籍的其他评论信息。为确保新内容能及时被加载,必须要根据自己网站的内容高度,调整到最佳的像素值。

接下来,需要修改HomeController添加检索书籍评论列表。为了确保最新的评论首先显示,排序使用创建日期降序的排列方法。为了减轻数据库的负载,每次只加载固定数量的评论而不是全部,但是也要保证,在滚动时显示足够的内容。在下面的示例当中,评论的加载数量将会限制为3条。页面的最大加载次数也被限制为评论总数除以3的结果。设置最大页数,以防止在加载完毕后,产生无效Ajax请求。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Globalization;
using System.Data.Entity;
using MvcApplication4.Models;
namespace MvcApplication4.Controllers
{
    public class HomeController : Controller
    {
        private BookDBContext db = new BookDBContext();
        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";
            
            // Get our recent comments
            var bookcomments = db.BookComments.Include(
                b => b.Book).OrderByDescending(b => b.Created).
                    Take(3);
            var count = db.BookComments.Count();
            ViewBag.maxPages = count / 3 + 1;
            return View(bookcomments);
        }
        ...
    }
}

接下来,需要复制一个新的异步控制器。选中Controllers文件夹,右键单击选择“添加”→“控制器”,将新控制器命名为“CommentFeedController”。这个控制器不需要设置基架选项以及其他内容,直接点击“添加”即可。(译者注:然后将新创建的控制器类的父类改为“AsyncController

这个控制器与之前的默认控制器看起来会有一些区别。异步控制器,每个视图都会有两个方法。第一个方法是用来实现异步请求(例如,获取评论信息)。第二个方法,是在异步调用时返回或显示接收到的结果。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using System.Data.Entity;

namespace MvcApplication4.Controllers
{
    public class CommentFeedController : AsyncController
    {
        private BookDBContext db = new BookDBContext();
        public void CommentsAsync(int page)
        {
            AsyncManager.OutstandingOperations.Increment();
            
            AsyncManager.Sync(() =>
            {
                var bookcomments = db.BookComments.Include(
                    b => b.Book).OrderByDescending(b =>
                        b.Created).Skip(page * 3).Take(3);
                AsyncManager.Parameters["bookcomments"] =
                    bookcomments;
                AsyncManager.OutstandingOperations.Decrement();
            });
        }
        
        public ActionResult CommentsCompleted(
            IEnumerable<BookComment> bookcomments)
        {
            return PartialView(bookcomments);
        }
    }
}

第一个方法,“CommentsAsync”,接收从Javascript传回的当前的页码,使用这个值来检索接下来的3条评论。首先是调用OutstandingOperations来通知未完成的请求挂起。然后再将检索评论的代码作为一个方法变量执行第二步操作,最后,再从未完成的计数器中将执行方法减去。在这里最重要的是递增和递减在计数器中的匹配,当递增和递减计数器相同的一段时间后,同步管理器将取消请求,否则,请求永远无法结束。

第二个方法,接收书籍的评论信息,并返回一个分部视图结果。这是一个与Home/Index视图相同的分部视图。在这里最后一步就是创建这个分部视图。右键单击“Views”文件夹,选择“添加”→“新建文件夹”,并将文件夹命名为“CommentFeed”,然后右键单击此文件夹,选择“添加”→“视图”,将其命名为“Comments”,然后确保选中创建视图对话框中的“创建分部视图”选项,然后点击“添加”。

@model IEnumerable<MvcApplication4.Models.BookComment>
@foreach (var item in Model) {
    <h3><a href="@Url.Action("Details", "Books", new {
            ID=item.Book.ID } )">
        @Html.DisplayFor(modelItem => item.Book.Title)
    </a></h3>
    <h4>Comment Posted: @Html.DisplayFor(
        modelItem => item.Created)</h4>
    <p>@MvcHtmlString.Create(Html.Encode(item.Comment).Replace(
        Environment.NewLine, "<br />"))</p>

}

如上所示,首先将评论按照创建时间排序循环取出,显示书籍标题以及详情链接,评论的创建日期以及最后的评论文本。因为评论中有可能会包含换行符,将其中换行符替换为“<br />”标记。

参考

Asynchronous Controllers 原书地址 书籍源代码

[转载]教你10分钟内在Windows上完成Rails开发环境的安装和配置

mikel阅读(1107)

[转载]教你10分钟内在Windows上完成Rails开发环境的安装和配置 – 开源天宝 – 博客园.

一般来说,Windows开发者需要自己搭建好Ruby、RubyGems、Rails以及SQLite才能开始创建Rails应用。

对于初学者,在Windwos上安装rails最简单的方式是RailsInstaller安装包。
RailsInstaller是一键安装的软件包,能够帮助你尽快上手,快速安装好开发环境。

本文使用的railsinstaller 2.0.1包含了:

RailsInstaller的官方网站http://railsinstaller.org/

1,railsinstaller 2.0.1版本下载快速通道:下载

2,双击railsinstaller.exe进行安装,是一个58m的文件。

3,railsinstaller安装步骤:

点击Next,进入下一步:

同意安装协议,进入下一步:

这一步设置文件安装的位置,推荐使用英文或者拼音,字母间一定不要带空格,方便以后通过cmd的方式进行操作,点击install进行安装。

点击finish完成安装。

railsinstaller的安装大概需要6分钟,安装后文件大小为437兆,如图。

点击完成后,会弹出git和shh的设置提示,如下图。

git是一个程序版本控制管理工具,需要到github.com上注册一个免费用户,注册步骤如下图。

注册后,回到刚才的cmd窗口,分别输入用户名和邮箱地址:

完成设置后,会提示sshkey已经复制到剪贴板,建立一个txt文件=>粘贴,把它保存下来,留着以后使用。程序同时在c盘下建立了一个sites的目录。

到这一步,整个ruby on rails的开发环境就配置好了,以后可以通过cmd来测试和使用,如下图:

可以看到安装的gem的版本是1.7.2,ruby 的版本是1.9.2,rails的版本是3.1.1。

到此,我们使用railsinstaller在windows上快速的安装了rails。

开始我们的ruby on rails之旅吧。

[转载]SQL模糊查询语句和Escape转义字符

mikel阅读(1386)

[转载]SQL模糊查询语句和Escape转义字符 – amylis – 博客园.

通配符 描述 示例
% 包含零个或更多字符的任意字符串。 WHERE title LIKE ‘%computer%’ 将查找处于书名任意位置的包含单词 computer 的所有书名。
_(下划线) 任何单个字符。 WHERE au_fname LIKE ‘_ean’ 将查找以 ean 结尾的所有 4 个字母的名字(Dean、Sean 等)。
[ ] 指定范围 ([a-f]) 或集合 ([abcdef]) 中的任何单个字符。 WHERE au_lname LIKE ‘[C-P]arsen’ 将查找以arsen 结尾且以介于 C 与 P 之间的任何单个字符开始的作者姓氏,例如,Carsen、Larsen、Karsen 等。
[^] 不属于指定范围 ([a-f]) 或集合 ([abcdef]) 的任何单个字符。 WHERE au_lname LIKE ‘de[^l]%’ 将查找以 de 开始且其后的字母不为 l 的所有作者的姓氏。
将通配符作为文字使用

可以将通配符模式匹配字符串用作文字字符串,方法是将通配符放在括号中。下表显示了使用 LIKE 关键字和 [ ] 通配符的示例。

符号 含义
LIKE ‘5[%]’ 5%
LIKE ‘[_]n’ _n
LIKE ‘[a-cdf]’ a、b、c、d 或 f
LIKE ‘[-acdf]’ -、a、c、d 或 f
LIKE ‘[ [ ]’ [
LIKE ‘]’ ]
LIKE ‘abc[_]d%’ abc_d 和 abc_de
LIKE ‘abc[def]’ abcd、abce 和 abcf

SQL模糊查询,使用like比较字,加上SQL里的通配符,请参考以下:

1、LIKE’Mc%’ 将搜索以字母 Mc 开头的所有字符串(如 McBadden)。
2、LIKE’%inger’ 将搜索以字母 inger 结尾的所有字符串(如 Ringer、Stringer)。
3、LIKE’%en%’ 将搜索在任何位置包含字母 en 的所有字符串(如 Bennet、Green、McBadden)。
4、LIKE’_heryl’ 将搜索以字母 heryl 结尾的所有六个字母的名称(如 Cheryl、Sheryl)。
5、LIKE'[CK]ars[eo]n’ 将搜索下列字符串:Carsen、Karsen、Carson 和 Karson(如 Carson)。
6、LIKE'[M-Z]inger’ 将搜索以字符串 inger 结尾、以从 M 到 Z 的任何单个字母开头的所有名称(如 Ringer)。
7、LIKE’M[^c]%’ 将搜索以字母 M 开头,并且第二个字母不是 c 的所有名称(如MacFeather)。
Escape 转义字符

用户输入如果没有任何限制的话,则必须对特殊字符进行变换。
如果对单引号不进行变换,则会发生数据库错误,甚至可能导致系统崩溃。
 
不过回避方法却非常简单,只要将单引号[']转换成两个单引号['']就可以了。
例:SELECT * FROM TBL WHERE COL = 'ABC''DEF';
模糊查询的语句虽然不会发生SQL错误,但是不进行回避的话,则无法得到要检索的值。
 
回避方法较单引号复杂。需要使用转义符。将[%]转为[\%][_]转为[\_],
 
然后再加上[ESCAPE '\']就可以了。
例:SELECT * FROM TBL WHERE COL LIKE 'ABC\%\_%' ESCAPE '\'; 
 
  最后一个%是通配符。
如果做日文项目的话,会出现全角字符的[][_],
 
而这两个全角字符同样会作为半角通配符处理。
 
所以在变换时,同时需要将全角的[][_]进行变换。
例:SELECT * FROM TBL WHERE COL LIKE 'ABC\%\_\\_%' ESCAPE '\';

变换成这样似乎结束了,可是不要忘了还有转义符自身,万一用户输入转义符的话,
以上的处理就会发生
SQL错误。所以也必须对转义符进行变换。变换方法就是将[\]转换为[\\]

例:SELECT * FROM TBL WHERE COL LIKE 'ABC\%\_\\\\_%' ESCAPE '\';
以上的操作都针对于一般的数据类型,如CHARVARCHAR2。
 
如果出现NCHARNVARCHAR2的话,以上的处理就会出现ORA-01425错误。
 
 
 
如果改成以下写法,则会发生ORA-01424错误。
SELECT * FROM TBL WHERE COL LIKE '%\_%' ESCAPE TO_NCHAR('\')
正确的写法应该是
SELECT * FROM TBL WHERE COL LIKEC '%\_%' ESCAPE TO_NCHAR('\')

 
最后要说明的是每个like都应该写ESCAPE语句。
例:
 
SELECT * FROM TBL 
 
WHERE COL1 LIKE '%\_%' ESCAPE '\' OR COL2 LIKE '%\_%' ESCAPE '\'

SQL> select * from test;

TEST
——————–
sdd_kk
d’d
dfsfsa
dffa%asfs
12345
1%2345
1%54321
2%54321
%%54321
A&B

已选择9行。

其中包含特殊的字符分别为%,_,&,有可能包含这些字符的数据含有错误,或者需要查找包含这些字符的数据。
SQL> select * from test where test like ‘sdd _%’ escape ‘ ‘;

TEST
——————–
sdd_kk

转义字符为’ ‘(空格);

SQL> select * from test where test like ‘sdd\_%’ escape ‘\’;

TEST
——————–
sdd_kk

转义字符为’\’;


SQL> select * from test where test like ‘sdd=_%’ escape ‘=’;

TEST
——————–
sdd_kk

转义字符为’=’;

SQL> select * from test where test like ‘sdd/_%’ escape ‘/’;

TEST
——————–
sdd_kk

转义字符为’/’;

SQL> select * from test where test like ‘sddd_%’ escape ‘d’;

未选定行

转义字符为d,没有实现转义功能;

SQL> select * from test where test like ‘%\_%’ escape ‘\’;

TEST
——————–
sdd_kk

查找包含所有’_’的字段。

同理:通过这种方法查找含有’%’的所有字段:

SQL> select * from test where test like ‘%\%%’ escape ‘\’;

TEST
——————–
dffa%asfs
1%2345
1%54321
2%54321
%%54321

但是’&’不能通过转义字符查找:

SQL> select * from test where test like ‘%\&%’ escape’\’;
select * from test where test like ‘%\&%’ escape’\’
*
第 1 行出现错误:
ORA-01424: 转义符之后字符缺失或非法

可以通过另外的方式进行转义:

SQL> select ascii(‘&’) from dual;

ASCII(‘&’)
———-
38

SQL> select * from test where test like ‘%’||chr(38)||’%’;

TEST
——————–
A&B

”’的转义:

SQL> select * from test where test like ‘%”%’;

TEST
——————–
d’d

特殊符号的数据的插入

SQL> insert into test values(‘test&test’);
输入 test 的值: test
原值    1: insert into test values(‘test&test’)
新值    1: insert into test values(‘testtest’)          -虽然插入,但是数据不对。

已创建 1 行。

SQL> show define
define “&” (hex 26)
SQL> set define off
SQL> show define
define OFF
SQL> insert into test values(‘test&test’);

已创建 1 行。

SQL> show escape
escape OFF
SQL> set escape on
SQL> show escape
escape “\” (hex 5c)
SQL> insert into test values(‘test\&test’);

已创建 1 行。

SQL> select * from test;

TEST
——————–
sdd_kk
d’d
dfsfsa
dffa%asfs
12345
1%2345
1%54321
2%54321
%%54321
A&B
testtest

TEST
——————–
test&test
test&test

已选择13行。

SQL> commit;

提交完成。

SQL> select * from test;

TEST
——————–
sdd_kk
d’d
dfsfsa
dffa%asfs
12345
1%2345
1%54321
2%54321
%%54321
A&B
testtest

TEST
——————–
test&test
test&test

已选择13行。

SQL> insert into test values(‘test\%test’);

已创建 1 行。

SQL> insert into test values(‘test\_test’);

已创建 1 行。

SQL> insert into test values(‘test\’test);
insert into test values(‘test’test)
*
第 1 行出现错误:
ORA-00917: 缺失逗号


SQL> insert into test values(‘test”test’);

已创建 1 行。

SQL> select * from test;

TEST
——————–
sdd_kk
d’d
dfsfsa
dffa%asfs
12345
1%2345
1%54321
2%54321
%%54321
A&B
testtest

TEST
——————–
test&test
test&test
test%test
test_test
test’test

已选择16行。

连接符‘||’导致了新一轮的转义:连接符号‘||’左右的单引号没有任何的关系,除非‘||’是作为字符串的一部分(这在动态SQL中很常见)。

SQL> SELECT ‘ORACLE’||”” FROM DUAL;

‘ORACLE’||”
———-
ORACLE’
个人理解,’ORACLE’||”” 后面的“”””应该认为是一个字符串(即前后单引号,中间是“””串,而中间又是密集单引号,因此第一个为转义功能)
SQL> SELECT ‘ORACLE””’ FROM DUAL;

‘ORACLE””’
————
ORACLE”
对于第一个,前两个单引号配对,后面四个单引号按照上面的第一条原则分配,既:SELECT ‘ORACLE’||”” FROM DUAL;
对于第二个,由于第二个单引号后面存在单引号,所以就不与第一个配对,而是充当了转义的角色。既:SELECT ‘ORACLE””’ FROM DUAL;

注:本人引用了网友的资源,如侵犯了您的版权,请告知,我会立即修改指明出处

[转载]让你的网页文本框增加光晕效果(类似QQ2011)

mikel阅读(1310)

[转载]让你的网页文本框增加光晕效果(类似QQ2011) – hmiinyu – 博客园.

我们都知道默认的ASP.NET文本框很丑陋的,看到QQ2011版的登录输入文本框那种光晕效果,不免让我们很是向往,不过我查看了源码却发现是通过C++实现的,那如何在我们的ASP.NET中添加同样的功能呢?先给大家秀一下我的运行截图:

默认文本框样式:

鼠标移入文本框:

是不是很酷呢?下面我将一一解释如何做出来的?首先我们建立一个WebSite应用程序。在开始做之前建立一个文件夹 plugins/textbox并引入JQuery库,在textbox子文件夹下再添加一个images文件夹(包含一张背景 图:border.png),大概的文件夹结构应该如下:

接着我们开始设计粗略版的html结构,大致如下:

<div class='span'>姓名</div>
<div class='aq_box'>
    <div class='aq_box_wrap'>
        <input type="text" id="name" class="textbox" label="姓名" />
    </div>
</div>

很简单把,我们发现其中有几个地方包含了class以及伪属性label,但是根据我的想法,希望将它做成插件,给用户调用,这样就很方便了。我先给出调用代码和html结构:

<head>
    <title></title>
    <link href="jquey.textbox.css" rel="stylesheet" type="text/css" />
    <script src="jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="jquery.textbox.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#name").textbox();
        });
    </script>
</head>
<body>
    <input type="text" id="name" class="textbox" label="姓名" />
</body>

是不是调用更简单了,封装的足够好了把。接下来,我将带大家编写更为关键的CSS和JQuery插件。

首先看插件,由于功能需求不妨命名为jQuery.textbox.js:

(function ($) {
    $.addTextBox = function (t, p) {
        p = $.extend({
            width: 174
        }, p);
        var span = $.trim($(t).attr("label"));
        if (span != "") {
            $(t).before("<div class='span'>" + span + "</div>");
        }
        $(t).wrap("<div class='aq_box'><div class='aq_box_wrap'></div></div>")
            .parents(".aq_box")
            .siblings().removeClass("hover").end()
            .hover(function () {
                $(this).toggleClass("hover");
            }, function () {
                $(this).toggleClass("hover");
            })
            .find(".textbox").width(p.width);
    };
    var docloaded = false;
    $(document).ready(function () {
        docloaded = true
    });
    $.fn.textbox = function (p) {
        return this.each(function () {
            if (!docloaded) {
                var t = this;
                $(document).ready(function () {
                    $.addTextBox(t, p);
                });
            } else {
                $.addTextBox(this, p);
            }
        });
    }; //end textbox
})(jQuery);

对插件中应用的样式文件(jQuery.textbox.css)在以下:

.span
{
    padding: 3px 2px 0 0;
    float: left;
    display: inline;
}
.textbox
{
    border: 0px;
    height: 22px;
    line-height: 22px;
    overflow: hidden;
    background: url(images/border.png) 0 -72px repeat-x;
}
.aq_box
{
    padding-left: 3px;
    background: url(images/border.png) left -24px no-repeat;
    float: left;
}
.aq_box_wrap
{
    padding-right: 3px;
    background: url(images/border.png) right -24px no-repeat;
}

.aq_box.hover
{
    background-position: left top;
}
.aq_box.hover .aq_box_wrap
{
    background-position: right top;
}
.aq_box.hover .textbox
{
    background-position: 0 -48px;
}

另外,我将背景图片(border.png)也贴上来,

这些准备工作做完之后,你就可以去浏览这些美妙的效果了。其实,这个功能还有很多改进的地方,比如可以添加水印,添加tooltip效果,添加搜索图标,添加键盘图标等等。我将在以后的插件开发中继续更新和完善,欢迎大家一起来欣赏。