天天看點

dbUtils 中各種 Handler 的使用

原貼:http://www.cnblogs.com/myit/p/4272824.html

  • ArrayHandler:把結果集中的第一行資料轉成對象數組。
  • ArrayListHandler:把結果集中的每一行資料都轉成一個對象數組,再存放到List中。
  • BeanHandler:将結果集中的第一行資料封裝到一個對應的JavaBean執行個體中。
  • BeanListHandler:将結果集中的每一行資料都封裝到一個對應的JavaBean執行個體中,存放到List裡。
  • ColumnListHandler:将結果集中某一列的資料存放到List中。
  •  KeyedHandler:将結果集中的每一行資料都封裝到一個Map裡,然後再根據指定的key把每個Map再存放到一個Map裡。
  •  MapHandler:将結果集中的第一行資料封裝到一個Map裡,key是列名,value就是對應的值。
  •  MapListHandler:将結果集中的每一行資料都封裝到一個Map裡,然後再存放到List。
  •  ScalarHandler:将結果集中某一條記錄的其中某一列的資料存成Object。

 單行資料處理:ScalarHandler    ArrayHandler    MapHandler    BeanHandler

      多行資料處理:BeanListHandler    AbstractListHandler(ArrayListHandler MapListHandler ColumnListHandler)

                          AbstractKeyedHandler(KeyedHandler BeanMapHandler)

      可供擴充的類:BaseResultSetHandler

      Dbutils使用結果集的方法有query、insert、insertBatch三個。這些方法都在QueryRunner類中,需要注意的是insert和update方法都能執行 “insert”開頭的sql語句,但是傳回值有差別。insert 執行後傳回的是表中的插入行生成的主鍵值,update 傳回的是受語句影響的行數。是以,如果目标表中有主鍵且需要傳回插入行的主鍵值就用 insert 方法,如果表沒有主鍵或者不需要傳回主鍵值可使用 update 方法。

      先建立測試用資料表[users]:

id userName loginName userPassword userLevel userLock
1 測試使用者1 test1 jiseflwes 10
2 知道什麼 hello 2556sefsfs 10 1
3 程式設計就程式設計 cjava sfsfsef254sefs 2

      字段類型,id 為主鍵:

1

2

3

4

5

6

[id] [

int

] IDENTITY(1,1)

NOT

NULL

,

[userName] [

nchar

](20)

NOT

NULL

,

[loginName] [

nchar

](20)

NOT

NULL

,

[userPassword] [

nchar

](100)

NOT

NULL

,

[userLevel] [

int

]

NOT

NULL

,

[userLock] [

bit

]

NOT

NULL

,

1、ScalarHandler<T>     

      用于擷取結果集中第一行某列的資料并轉換成 T 表示的實際對象。

      該類對結果集的處理直接在 handle 方法中進行,不涉及 dbutils 庫的其他類。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

String sql =

"select * from users"

;

// ---- query 語句 ----

// ScalarHandler 的參數為空或null時,傳回第一行第一列的資料

int

rs = runner.query(sql,

new

ScalarHandler<Integer>());

System.out.println(

"ScalarHandler: "

+ rs);

// Print:[ScalarHandler: 1]

// ScalarHandler 的參數可以是列的索引(從1開始)或列名

String rs = runner.query(sql,

new

ScalarHandler<String>(

2

));

// 或者 String rs = runner.query(sql, new ScalarHandler<String>("userName"));

System.out.println(

"ScalarHandler: "

+ rs);

// Print:[ScalarHandler: 測試使用者1]

// ---- insert 語句 ----

// 因為我使用的是mssql資料庫,QueryRunner的insert擷取插入資料的主鍵其實調用的是select SCOPE_IDENTITY()

// 資料庫執行後傳回的類型是numeric,映射到 java 類型就是 java.math.BigDecimal

String inSql =

"insert users (userName, loginName, userPassword, userLevel, userLock) values (?, ?, ?, ?, ?)"

;

BigDecimal insertRs = runner.insert(inSql,

new

ScalarHandler(), 

"java程式編寫"

,

"javahello"

,

"sefsfsfwew"

,

"15"

,

false

);

System.out.println(

"ScalarHandler: "

+ insertRs);

// Print:[ScalarHandler: 4]

      使用的時候一定要保證提供正确的列索引或列名,并且結果類型也要正确可轉換。

2、ArrayHandler

      用于擷取結果集中的第一行資料,并将其封裝到一個數組中,一列值對應一個數組元素。

      handle 源碼:

1

2

3

4

5

public

Object[] handle(ResultSet rs)

throws

SQLException {

// convert = new BasicRowProcessor()

// 如果有資料,将調用 BasicRowProcessor 的 toArray(rs) 方法處理

return

rs.next() ?

this

.convert.toArray(rs) : EMPTY_ARRAY;

}

1

2

3

4

5

6

7

8

9

10

11

// ---- query 語句 ----

String sql =

"select * from users"

;

Object[] rs = runner.query(sql,

new

ArrayHandler());

// Print: ArrayHandler: [1, 測試使用者1, test1, jiseflwes, 10, false]

System.out.println(

"ArrayHandler: "

+ Arrays.toString(rs));

// ---- insert 語句 ----

String inSql =

"insert users_t (userName, loginName, userPassword, userLevel, userLock) values (?, ?, ?, ?, ?)"

;

Object[] insertRs = runner.insert(inSql,

new

ArrayHandler(), 

"java程式編寫"

,

"javahello"

,

"sefsfsfwew"

,

"15"

,

false

);

// Print: ArrayHandler: [5]

System.out.println(

"ArrayHandler: "

+ Arrays.toString(insertRs));

3、MapHandler

      用于擷取結果集中的第一行資料,并将其封裝到一個Map中,Map 中 key 是資料的列别名(as label),如果沒有就是列的實際名稱,Map 中 value 就是列的值,注意代表列的 key 不區分大小寫。

      handle 源碼:

1

2

3

4

5

public

Map<String, Object> handle(ResultSet rs)

throws

SQLException {

// convert = new BasicRowProcessor()

// 如果有資料,将調用 BasicRowProcessor 的 toMap(rs) 方法處理

return

rs.next() ?

this

.convert.toMap(rs) :

null

;

}

      通過檢視 BasicRowProcessor 代碼,可以知道封裝結果集的 Map 其實是一個 LinkedHashMap 對象。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

// ---- query 語句 ----

String sql =

"select userName, loginName, userPassword as password, userLevel, userLock from users"

;

Map<String, Object> rs = runner.query(sql,

new

MapHandler());

// Print: MapHandler: {userName=測試使用者1, loginName=test1, password=jiseflwes, userLevel=10, userLock=false}

System.out.println(

"MapHandler: "

+ rs);

// 列名小寫 Print: username: 測試使用者1

System.out.println(

"username: "

+ rs.get(

"username"

));

// 列名大寫 Print: USERNAME: 測試使用者1

System.out.println(

"USERNAME: "

+ rs.get(

"USERNAME"

));

// 使用了as指定别名,那麼取資料的時候一定要用别名,否則傳回null。

// Print: userPassword as password: jiseflwes

System.out.println(

"userPassword as password: "

+ rs.get(

"password"

));

// Print: userPassword as password: null

System.out.println(

"userPassword as password: "

+ rs.get(

"userPassword"

));

// ---- insert 語句 ----

String inSql =

"insert users (userName, loginName, userPassword, userLevel, userLock) values (?, ?, ?, ?, ?)"

;

Map<String, Object> insertRs = runner.insert(inSql,

new

MapHandler(), 

"java程式編寫"

,

"javahello"

,

"sefsfsfwew"

,

"15"

,

false

);

// 注意這個鍵(key)是由資料庫驅動定義的。

// Print: MapHandler:{GENERATED_KEYS=6}

System.out.println(

"MapHandler: "

+ insertRs);

// 我用的是微軟提供的驅動,是以是GENERATED_KEYS,如果是其他驅動就又不同了(比如jtds驅動key是ID)

// jtds驅動使用 insertRs.get("ID")

// Print: MapHandler: 6

System.out.println(

"MapHandler: "

+ insertRs.get(

"GENERATED_KEYS"

));

4、BeanHandler<T>

      用于擷取結果集中的第一行資料,并将其封裝到JavaBean對象。

      整個轉換過程最終會在 BeanProcessor 類中完成。

      執行代碼:

這裡是擷取全部,但是用了beanhandler就變成了第一行

//---- query 語句 ----

String sql = "select * from users";

Users rs = runner.query(sql, new BeanHandler<Users>(Users.class));
           

1

2

3

4

5

6

7

// Print: BeanHandler: Users{id=1, userName='測試使用者1', loginName='test1', userPassword='jiseflwes', userLevel=10, userLock=true}

System.out.println(

"BeanHandler: "

+ rs);

// Print: BeanHandler: test1

System.out.println(

"BeanHandler: "

+ rs.getLoginName());

dbUtils 中各種 Handler 的使用

可以省略<>中的類型

需要注意的是,預設的情況下要保證表的字段和javabean的屬性一緻(字元一緻即可,對大小寫不敏感),比如字段是userLock,那麼javabean中屬性必須是userLock這幾個字母(可以是userlock,userLock,userLOCK,不過還是建議按照規範來定義)。

      但有個問題,資料表中的字段可能已經定下來了,而且名稱可能不太規範,比如用下劃線(login_name),或者加了一個類型字首(chrLoginName),如果修改表字段,那麼涉及到的修改地方太多了,其實檢視源碼可以知道BeanHandler有兩個構造方法:

1

2

3

4

5

6

7

8

// BeanHandler 構造方法

public

BeanHandler(Class<T> type) {

this

(type, ArrayHandler.ROW_PROCESSOR);

}

public

BeanHandler(Class<T> type, RowProcessor convert) {

this

.type = type;

this

.convert = convert;

}

      可以看出其實都是調用的第二個方法。

1

2

3

4

5

6

runner.query(sql,

new

BeanHandler<Users>(Users.

class

));

// 等價于

runner.query(sql,

new

BeanHandler<Users>(Users.

class

,

new

BasicRowProcessor()));

// 等價于

runner.query(sql,

new

BeanHandler<Users>(Users.

class

,

new

BasicRowProcessor(

new

BeanProcessor())));

// 是以關鍵的地方在 new BeanProcessor() 這個具體處理結果的對象

      情況一:隻涉及到下劃線,表字段名用下劃線間隔(如表users_t字段:[id],[user_name],[login_name],[user_password],[user_level],[user_lock]),現在要封裝到Javabean中Users類(代碼見上),其中屬性使用駝峰命名。可以用dbutils1.6提供的BeanProcessor類的子類GenerousBeanProcessor。

1

2

3

4

5

6

7

8

9

10

String sql =

"select id,user_name,login_name,user_password,user_level,user_lock from users_t"

;

// 建立一個BeanProcessor對象

// GenerousBeanProcessor 僅僅重寫了父類BeanProcessor的mapColumnsToProperties方法

BeanProcessor bean =

new

GenerousBeanProcessor();

// 将GenerousBeanProcessor對象傳遞給BasicRowProcessor

RowProcessor processor =

new

BasicRowProcessor(bean);

// 最後使用GenerousBeanProcessor的mapColumnsToProperties處理表字段到javabean的屬性映射

Users rs = runner.query(sql,

new

BeanHandler<Users>(Users.

class

, processor));

// Print: BeanHandler: Users{id=1, userName='測試使用者1', loginName='test1', userPassword='jiseflwes', userLevel=10, userLock=true}

System.out.println(

"BeanHandler: "

+ rs);

      情況二:完全改變表字段到Javabean屬性的映射(如表users_m字段:[yhmid],[charUsername],[charLoginName],[charPassword],[intLevel],[boolLock])映射到Users類(代碼同上):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// BeanProcessor 有兩個構造方法,可以傳入一個HashMap集合

// HashMap 規定了表字段映射到Javabean的哪個屬性,即key為字段名稱,value為對應的javabean屬性

// map.put(表字段名稱, Javabean屬性名稱)

Map<String, String> map =

new

HashMap<String, String>();

map.put(

"yhmid"

,

"id"

);

map.put(

"charUsername"

,

"userName"

);

map.put(

"charLoginName"

,

"loginName"

);

map.put(

"charPassword"

,

"userPassword"

);

map.put(

"intLevel"

,

"userLevel"

);

map.put(

"boolLock"

,

"userLock"

);

// 用建構好的HashMap建立一個BeanProcessor對象

BeanProcessor bean =

new

BeanProcessor(map);

RowProcessor processor =

new

BasicRowProcessor(bean);

Users rs = runner.query(sql,

new

BeanHandler<Users>(Users.

class

, processor));

// Print: BeanHandler: Users{id=1, userName='測試使用者1', loginName='test1', userPassword='jiseflwes', userLevel=10, userLock=true}

System.out.println(

"BeanHandler: "

+ rs);

5、BeanListHandler<T>

      用于将結果集的每一行資料轉換為Javabean,再将這個Javabean添加到ArrayList中。可以簡單的看着是BeanHandler的進階版,隻不過是多了一步,就是将生成的Javabean添加到ArrayList中,其他的處理都和BeanHandler一樣。

1

2

3

4

5

6

7

String sql =

"select * from users"

;

List<Users> rs = runner.query(sql,

new

BeanListHandler<Users>(Users.

class

));

// Print: BeanListHandler: [

// Users{id=1, userName='測試使用者1', loginName='test1', userPassword='jiseflwes', userLevel=10, userLock=true},

// Users{id=1, userName='知道什麼', loginName='hello', userPassword='2556sefsfs', userLevel=10, userLock=true},

// Users{id=1, userName='程式設計就程式設計', loginName='cjava', userPassword='sfsfsef254sefs', userLevel=2, userLock=false}]

System.out.println(

"BeanListHandler: "

+ rs);

6、AbstractListHandler<T>

1

2

3

4

5

6

7

8

9

// AbstractListHandler 類實作了handle方法

@Override

public

List<T> handle(ResultSet rs)

throws

SQLException {

List<T> rows =

new

ArrayList<T>();

while

(rs.next()) {

rows.add(

this

.handleRow(rs));

// 每個子類實作自己的handleRow方法

}

return

rows;

}

      AbstractListHandler抽象類已經實作handle方法,該方法其實隻是起到一個包裝作用,将處理好的每行資料添加到ArrayList中。每行的資料處理通過調用handleRow方法實作,所有它的3個子類都必須實作這個方法。

6.1 ArrayListHandler (extends AbstractListHandler<Object[]>)

      用于将結果集每行資料轉換為Object數組(處理過程等同與ArrayHandler),再将該數組添加到ArrayList中。簡單點,就是将每行資料經過ArrayHandler處理後添加到ArrayList中。

1

2

3

4

5

6

7

8

9

String sql =

"select * from users"

;

List rs = runner.query(sql,

new

ArrayListHandler());

// Print:

// [1, 測試使用者1, test1, jiseflwes, 10, true]

// [2, 知道什麼, hello, 2556sefsfs, 10, true]

// [3, 程式設計就程式設計, cjava, sfsfsef254sefs, 2, false]

for

(Object user : rs) {

System.out.println(Arrays.toString((Object[])user));

}

6.2 MapListHandler (extends AbstractListHandler<Map<String, Object>>)

      用于将結果集每行資料轉換為Map(處理過程等同與MapHandler),再将Map添加到ArrayList中。簡單點,就是将每行資料經過MapHandler處理後添加到ArrayList中。

1

2

3

4

5

6

7

8

9

String sql =

"select * from users"

;

List rs = runner.query(sql,

new

MapListHandler());

// Print:

// {1, 測試使用者1, test1, jiseflwes, 10, true}

// {2, 知道什麼, hello, 2556sefsfs, 10, true}

// {3, 程式設計就程式設計, cjava, sfsfsef254sefs, 2, false}

for

(Object user : rs) {

System.out.println((Map<String, Object>)user);

}

6.3 ColumnListHandler<T> (extends AbstractListHandler<T>)

      根據列索引或列名擷取結果集中某列的所有資料,并添加到ArrayList中。可以了解為ScalarHandler<T>的加強版。

1

2

3

4

5

6

7

8

9

10

String sql =

"select * from users"

;

List<String> rs = runner.query(sql,

new

ColumnListHandler<String>(

2

));

// 等同 List<String> rs = runner.query(sql, new ColumnListHandler<String>("userName"));

// Print:

// 測試使用者1

// 知道什麼

// 程式設計就程式設計

for

(String user : rs) {

System.out.println(user);

}

7、AbstractKeyedHandler<K, V>

     AbstractKeyedHandler是一個抽象類,已經實作了handle方法,其子類必須實作createKey(ResultSet rs)和createRow(ResultSet rs)方法,以便handle()的調用。

1

2

3

4

5

6

7

8

9

10

11

12

13

@Override

public

Map<K, V> handle(ResultSet rs)

throws

SQLException {

Map<K, V> result = createMap();

while

(rs.next()) {

result.put(createKey(rs), createRow(rs));

// 需要子類自己實作

}

return

result;

}

7.1 KeyedHandler<K> (extends AbstractKeyedHandler<K, Map<String, Object>>)

      用于擷取所有結果集,将每行結果集轉換為Map<String, Object>,并指定某列為key。可以簡單的認為是一個雙層Map,相當于先對每行資料執行MapHandler,再為其指定key添加到一個HaspMap中。KeyedHandler<K> 中的<K>是指定的列值的類型。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

String sql =

"select * from users"

;

// 在這兒指定主鍵id為結果key,也可以傳入列名 new KeyedHandler<Integer>("id")

Map<Integer, Map<String, Object>> rs = runner.query(sql,

new

KeyedHandler<Integer>(

1

));

// Print: KeyedHandler: {

//        1={id=1, userName=測試使用者1, loginName=test1, userPassword=jiseflwes, userLevel=10, userLock=true},

//        2={id=2, userName=知道什麼, loginName=hello, userPassword=2556sefsfs, userLevel=10, userLock=true},

//        3={id=3, userName=程式設計就程式設計, loginName=cjava, userPassword=sfsfsef254sefs, userLevel=2, userLock=false}}

System.out.println(

"KeyedHandler: "

+ rs);

// 也可以指定其他列作為key,但是需要注意如果指定的列值存在重複值,那麼後面的值将覆寫前面的,最終HashMap中key都是唯一的。

// 如指定列userLevel為key,最終隻有兩個結果,因為前兩行userLevel值都是10。

Map<Integer, Map<String, Object>> rs = runner.query(sql,

new

KeyedHandler<Integer>(

"userLevel"

));

// Print: KeyedHandler: {

//        2={id=3, userName=程式設計就程式設計, loginName=cjava, userPassword=sfsfsef254sefs, userLevel=2, userLock=false},

//        10={id=2, userName=知道什麼, loginName=hello, userPassword=2556sefsfs, userLevel=10, userLock=true}}

System.out.println(

"KeyedHandler: "

+ rs);

7.2 BeanMapHandler<K, V> (extends AbstractKeyedHandler<K, V>)

       用于擷取所有結果集,将每行結果集轉換為Javabean作為value,并指定某列為key,封裝到HashMap中。相當于對每行資料的做BeanHandler一樣的處理後,再指定列值為Key封裝到HashMap中。

1

2

3

4

5

6

7

8

String sql =

"select * from users"

;

// new BeanMapHandler<Integer, Users>(Users.class,"id")

Map<Integer, Users> rs = runner.query(sql,

new

BeanMapHandler<Integer, Users>(Users.

class

,

1

));

// Print: BeanMapHandler: {

// 1=Users{id=1, userName='測試使用者1', loginName='test1', userPassword='jiseflwes', userLevel=10, userLock=true},

// 2=Users{id=2, userName='知道什麼', loginName='hello', userPassword='2556sefsfs', userLevel=10, userLock=true},

// 3=Users{id=3, userName='程式設計就程式設計', loginName='cjava', userPassword='sfsfsef254sefs', userLevel=2, userLock=false}}

System.out.println(

"BeanMapHandler: "

+ rs);

       需要注意這個結果轉換類也可以像BeanHandler的情況一和情況二介紹的那樣定義一個processor,但預設情況下這麼做了就會以每行的第一列作為Key,不能指定其他列為Key。

1

2

// 這種情況下,以每行第一列為key

Map<Integer, Users> rs = runner.query(sql,

new

BeanMapHandler<Integer, Users>(Users.

class

,processor));

8、BaseResultSetHandler<T>

        根據文檔介紹,如果上面的結果集處理類都不能滿足你的要求,可以通過繼承這個抽象類定義自己的結果處理類,子類必須實作無參方法handle()。

        做個簡單的例子,比如要将指定列值加一個字首"class-"後添加到ArrayList中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

//------------- 定義類 MeResultHandler.java -------------

public

class

MeResultHandler

extends

BaseResultSetHandler<List<String>> {

private

final

int

columnIndex;

// 指定要擷取值的列索引

public

MeResultHandler(

int

columnIndex) {

this

.columnIndex = columnIndex;

}

// 重寫父類的方法,封裝每行資料

@Override

protected

List<String> handle()

throws

SQLException {

List<String> rows =

new

ArrayList<String>();

// 因為父類已經封裝好了對ResultSet各種操作,直接調用父類方法 next()

while

(

this

.next()) {

rows.add(handleRow());

}

return

rows;

}

// 自定義的資料處理方法

@SuppressWarnings

(

"unchecked"

)

private

String handleRow()

throws

SQLException {

// 直接調用父類方法 getObject()

return

"class-"

+ String.valueOf(

this

.getObject(

this

.columnIndex));

}

}

//------------- 使用類 -------------

List<String> rs = runner.query(sql,

new

MeResultHandler(

1

));

// Print: MeResultHandler: [class-1, class-2, class-3]

System.out.println(

"MeResultHandler: "

+ rs);

   ======================================================================

      總的來說,最終的資料處理是在 BasicRowProcessor 的四個方法中進行,涉及到JavaBean的話會通過 BasicRowProcessor 調用 BeanProcessor 的兩個方法。其他的都是對每行資料轉換後的結果的封裝。

dbUtils 中各種 Handler 的使用

繼續閱讀