博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mybatis3温故
阅读量:6875 次
发布时间:2019-06-26

本文共 30678 字,大约阅读时间需要 102 分钟。

MyBatis可以利用SQL映射文件来配置,也可以利用Annotation来设置。MyBatis提供的一些基本注解如下表所示。

注解

目标

相应的XML

描述

@CacheNamespace

<cache>  

为给定的命名空间(比如类)配置缓存。属性:

implemetation,eviction,

flushInterval , size 和 readWrite 。

@CacheNamespaceRef

<cacheRef>

参照另外一个命名空间的缓存来使用。

属性:value,也就是类的完全限定名。

@ConstructorArgs

方法

<constructor>

收集一组结果传递给对象构造方法。

属性:value,是形式参数的数组

@Arg

方法

<arg>

<idArg>

 

单独的构造方法参数,是ConstructorArgs  集合的一部分。属性:id,column,javaType,typeHandler。

id属性是布尔值,来标识用于比较的属性,和<idArg>XML 元素相似

@TypeDiscriminator

方法

<discriminator>

一组实例值被用来决定结果映射的表

现。属性:Column, javaType ,  jdbcType typeHandler,cases。

cases属性就是实例的数组。

@Case

方法

<case>

单独实例的值和它对应的映射。属性:value  ,type ,results 。

Results 属性是结果数组,因此这个注解和实际的ResultMap 很相似,由下面的  Results注解指定

@Results

方法

<resultMap>

结果映射的列表,包含了一个特别结果

列如何被映射到属性或字段的详情。

属性:value ,是Result注解的数组

@Result

方法

<result>

<id>

在列和属性或字段之间的单独结果映

射。属性:id ,column , property ,

javaType ,jdbcType ,type Handler ,

one,many。id 属性是一个布尔值,表

示了应该被用于比较的属性。one 属性是单独的联系,和 <association> 相似,而many 属性是对集合而言的,和

<collection>相似。

@One

方法

<association>  

复杂类型的单独属性值映射。属性:

select,已映射语句(也就是映射器方

法)的完全限定名,它可以加载合适类

型的实例。注意:联合映射在注解 API

中是不支持的。

@Many

方法

<collection>

复杂类型的集合属性映射。属性:

select,是映射器方法的完全限定名,它可加载合适类型的一组实例。注意:联合映射在Java注解中是不支持的。

@Options

方法

映射语句的属性

这个注解提供访问交换和配置选项的宽广范围,它们通常在映射语句上作为属性出现。而不是将每条语句注解变复杂,Options 注解提供连贯清晰的方式来访问它们。属性:useCache=true,

flushCache=false,

resultSetType=FORWARD_ONLY,

statementType=PREPARED,

fetchSize= -1,timeout=-1 ,

useGeneratedKeys=false ,

keyProperty=”id“。

理解Java 注解是很重要的,因为没有办法来指定“null ”作为值。因此,一旦你使用了Options注解,语句就受所有默认值的支配。要注意什么样的默认值来避免不期望的行为

@Insert

@Update

@Delete

方法

<insert>

<update>

<delete>

这些注解中的每一个代表了执行的真实 SQL。它们每一个都使用字符串数组(或单独的字符串)。如果传递的是字符串数组,它们由每个分隔它们的单独空间串联起来。属性:value,这是字符串数组用来组成单独的SQL语句

@InsertProvider

@UpdateProvider

@DeleteProvider

@SelectProvider

方法

<insert>

<update>

<delete>

<select>

允许创建动态

SQL。

这些可选的SQL注解允许你指定一个

类名和一个方法在执行时来返回运行

的SQL。基于执行的映射语句, MyBatis

会实例化这个类,然后执行由 provider

指定的方法. 这个方法可以选择性的接

受参数对象作为它的唯一参数,但是必

须只指定该参数或者没有参数。属性:

type,method。type 属性是类的完全限定名。method  是该类中的那个方法名。

@Param

参数

N/A

当映射器方法需多个参数,这个注解可以被应用于映射器方法参数来给每个参数一个名字。否则,多参数将会以它们的顺序位置来被命名。比如

#{1},#{2} 等,这是默认的。

使用@Param(“person”),SQL中参数应该被命名为#{person}。

这些注解都是运用到传统意义上映射器接口中的方法、类或者方法参数中的。

今天主要介绍两种使用注解的方式。

一种是直接在映射器接口中写SQL语句,一种是利用SqlBuilder来创建SQL再由映射器接口来调用

准备前提:

1,配置常规的MyBatis主配置文件,即各种数据源,别名等设置。在利用注解配置SQL的时候,一般不需要在主配置文件中配置Mapper,个别情况下需要配置。

2,数据库表Blog:

1
2
3
4
5
6
7
8
9
DROP 
TABLE 
IF EXISTS `blog`;
CREATE 
TABLE 
`blog` (
  
`id` 
int
(10) 
NOT 
NULL 
auto_increment,
  
`title` 
varchar
(200) 
NOT 
NULL
,
  
`
date
varchar
(50) 
NOT 
NULL
,
  
`authername` 
varchar
(15) 
NOT 
NULL
,
  
`content` 
varchar
(500) 
NOT 
NULL
,
  
PRIMARY 
KEY  
(`id`)
) ENGINE=InnoDB 
DEFAULT 
CHARSET=utf8;

 数据库表User:

1
2
3
4
5
6
7
8
DROP 
TABLE 
IF EXISTS `
user
`;
CREATE 
TABLE 
`
user
` (
  
`id` 
int
(11) 
NOT 
NULL 
auto_increment,
  
`userName` 
varchar
(50) 
default 
NULL
,
  
`userAge` 
int
(11) 
default 
NULL
,
  
`userAddress` 
varchar
(200) 
default 
NULL
,
  
PRIMARY 
KEY  
(`id`)
) ENGINE=InnoDB 
DEFAULT 
CHARSET=utf8;

3,分别写User和Blog对应的JavaBean即setter和getter实体类。

第一种 映射器接口中写SQL语句

映射器接口注解

 

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
package 
com.whut.inter;
import 
java.util.List;
import 
org.apache.ibatis.annotations.Delete;
import 
org.apache.ibatis.annotations.Insert;
import 
org.apache.ibatis.annotations.Param;
import 
org.apache.ibatis.annotations.Select;
import 
org.apache.ibatis.annotations.Update;
import 
com.whut.model.User;
//最基本的注解CRUD
public 
interface 
IUserDAO {
    
@Select
(
"select *from User"
)
    
public 
List<User> retrieveAllUsers();
                                                                                                                                                                                                                                   
    
//注意这里只有一个参数,则#{}中的标识符可以任意取
    
@Select
(
"select *from User where id=#{idss}"
)
    
public 
User retrieveUserById(
int 
id);
                                                                                                                                                                                                                                   
    
@Select
(
"select *from User where id=#{id} and userName like #{name}"
)
    
public 
User retrieveUserByIdAndName(
@Param
(
"id"
)
int 
id,
@Param
(
"name"
)String names);
                                                                                                                                                                                                                                   
    
@Insert
(
"INSERT INTO user(userName,userAge,userAddress) VALUES(#{userName},"
            
"#{userAge},#{userAddress})"
)
    
public 
void 
addNewUser(User user);
                                                                                                                                                                                                                                   
    
@Delete
(
"delete from user where id=#{id}"
)
    
public 
void 
deleteUser(
int 
id);
                                                                                                                                                                                                                                   
    
@Update
(
"update user set userName=#{userName},userAddress=#{userAddress}"
            
" where id=#{id}"
)
    
public 
void 
updateUser(User user);
}

测试代码:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package 
com.whut.test;
import 
java.io.IOException;
import 
java.io.Reader;
import 
java.util.List;
import 
org.apache.ibatis.io.Resources;
import 
org.apache.ibatis.session.SqlSession;
import 
org.apache.ibatis.session.SqlSessionFactory;
import 
org.apache.ibatis.session.SqlSessionFactoryBuilder;
import 
com.whut.inter.IUserDAO;
import 
com.whut.model.User;
public 
class 
TestUser {
    
private 
static 
SqlSessionFactory sqlSessionFactory;
    
private 
static 
Reader reader;
    
static 
{
        
try 
{
            
Reader reader = Resources.getResourceAsReader(
"mybatic-config.xml"
);
            
sqlSessionFactory = 
new 
SqlSessionFactoryBuilder().build(reader);
            
// 由于使用了注解,所以在主配置文件没有mapper,需要在代码里显示注册该mapper接口
            
sqlSessionFactory.getConfiguration().addMapper(IUserDAO.
class
);
        
catch 
(IOException e) {
            
e.printStackTrace();
        
}
    
}
    
public 
static 
void 
main(String[] args) {
        
// testSelectAll();
        
// testSelectByConditions();
        
//testAddUser();
        
//testDeleteUser();
                                                                                                                                                                                                                
        
testUpateUser();
    
}
    
public 
static 
void 
testSelectAll() {
        
// sqlSessionFactory.getConfiguration().addMapper(IUserDAO.class);
        
SqlSession session = sqlSessionFactory.openSession();
        
try 
{
            
IUserDAO userDAO = session.getMapper(IUserDAO.
class
);
            
List<User> users = userDAO.retrieveAllUsers();
            
System.out.println(
"用户编号\t" 
"姓名\t" 
"年龄\t住址"
);
            
for 
(User u : users) {
                
System.out.println(u.getId() + 
"\t" 
+ u.getUserName() + 
"\t"
                        
+ u.getUserAge() + 
"\t" 
+ u.getUserAddress());
            
}
        
finally 
{
            
session.close();
        
}
    
}
    
public 
static 
void 
testSelectByConditions() {
        
SqlSession session = sqlSessionFactory.openSession();
        
try 
{
            
IUserDAO userDAO = session.getMapper(IUserDAO.
class
);
            
User u = userDAO.retrieveUserByIdAndName(
4
"%spring%"
);
            
if 
(u != 
null
) {
                
System.out.println(
"用户编号\t" 
"姓名\t" 
"年龄\t住址"
);
                
System.out.println(u.getId() + 
"\t" 
+ u.getUserName() + 
"\t"
                        
+ u.getUserAge() + 
"\t" 
+ u.getUserAddress());
            
}
        
finally 
{
            
session.close();
        
}
    
}
    
public 
static 
void 
testAddUser() {
        
User u = 
new 
User();
        
u.setUserName(
"dongtian"
);
        
u.setUserAge(
51
);
        
u.setUserAddress(
"hubeisheng"
);
        
SqlSession session = sqlSessionFactory.openSession();
        
try 
{
            
IUserDAO userDAO = session.getMapper(IUserDAO.
class
);
            
userDAO.addNewUser(u);
            
session.commit();
        
finally 
{
            
session.close();
        
}
    
}
    
public 
static 
void 
testDeleteUser() {
        
SqlSession session = sqlSessionFactory.openSession();
        
try 
{
            
IUserDAO userDAO = session.getMapper(IUserDAO.
class
);
            
userDAO.deleteUser(
7
);
            
session.commit();
        
finally 
{
            
session.close();
        
}
    
}
                                                                                                                                                                                                            
    
public 
static 
void 
testUpateUser() {
        
User u = 
new 
User();
        
u.setId(
4
);
        
u.setUserName(
"dongtian"
);
        
u.setUserAge(
51
);
        
u.setUserAddress(
"hubeisheng"
);
        
SqlSession session = sqlSessionFactory.openSession();
        
try 
{
            
IUserDAO userDAO = session.getMapper(IUserDAO.
class
);
            
userDAO.updateUser(u);
            
session.commit();
        
finally 
{
            
session.close();
        
}
    
}
}

 

第二种 映射器接口调用SqlBuilder生成的SQL进行执行

映射器接口

 

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package 
com.whut.inter;
import 
java.util.List;
import 
org.apache.ibatis.annotations.CacheNamespace;
import 
org.apache.ibatis.annotations.DeleteProvider;
import 
org.apache.ibatis.annotations.InsertProvider;
import 
org.apache.ibatis.annotations.Options;
import 
org.apache.ibatis.annotations.Param;
import 
org.apache.ibatis.annotations.Result;
import 
org.apache.ibatis.annotations.ResultMap;
import 
org.apache.ibatis.annotations.Results;
import 
org.apache.ibatis.annotations.SelectProvider;
import 
org.apache.ibatis.annotations.UpdateProvider;
import 
org.apache.ibatis.type.JdbcType;
import 
com.whut.model.Blog;
import 
com.whut.sqlTool.BlogSqlProvider;
@CacheNamespace
(size=
100
)
public 
interface 
IBlogDAO {
    
@SelectProvider
(type = BlogSqlProvider.
class
, method = 
"getSql"
)
    
@Results
(value ={
            
@Result
(id=
true
, property=
"id"
,column=
"id"
,javaType=Integer.
class
,jdbcType=JdbcType.INTEGER),
            
@Result
(property=
"title"
,column=
"title"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
@Result
(property=
"date"
,column=
"date"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
@Result
(property=
"authername"
,column=
"authername"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
@Result
(property=
"content"
,column=
"content"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
})
    
public 
Blog getBlog(
@Param
(
"id"
int 
id);
                                                                                                                                                                                       
    
@SelectProvider
(type = BlogSqlProvider.
class
, method = 
"getAllSql"
)
    
@Results
(value ={
            
@Result
(id=
true
, property=
"id"
,column=
"id"
,javaType=Integer.
class
,jdbcType=JdbcType.INTEGER),
            
@Result
(property=
"title"
,column=
"title"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
@Result
(property=
"date"
,column=
"date"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
@Result
(property=
"authername"
,column=
"authername"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
@Result
(property=
"content"
,column=
"content"
,javaType=String.
class
,jdbcType=JdbcType.VARCHAR),
            
})
    
public 
List<Blog> getAllBlog();
                                                                                                                                                                                       
    
@SelectProvider
(type = BlogSqlProvider.
class
, method = 
"getSqlByTitle"
)
    
@ResultMap
(value = 
"sqlBlogsMap"
)
    
//这里调用resultMap,这个是SQL配置文件中的,必须该SQL配置文件与本接口有相同的全限定名
    
//注意文件中的namespace路径必须是使用@resultMap的类路径
    
public 
List<Blog> getBlogByTitle(
@Param
(
"title"
)String title);
                                                                                                                                                                                       
    
@InsertProvider
(type = BlogSqlProvider.
class
, method = 
"insertSql"
)
    
public 
void 
insertBlog(Blog blog);
                                                                                                                                                                                       
    
@UpdateProvider
(type = BlogSqlProvider.
class
, method = 
"updateSql"
)
    
public 
void 
updateBlog(Blog blog);
                                                                                                                                                                                       
    
@DeleteProvider
(type = BlogSqlProvider.
class
, method = 
"deleteSql"
)
    
@Options
(useCache = 
true
, flushCache = 
false
, timeout = 
10000
)
    
public 
void 
deleteBlog(
int 
ids);
                                                                                                                                                                                       
}

 

SQL生成器(利用SqlBuilder生成)

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package 
com.whut.sqlTool;
import 
java.util.Map;
import 
static 
org.apache.ibatis.jdbc.SqlBuilder.*;
public 
class 
BlogSqlProvider {
    
private 
final 
static 
String TABLE_NAME = 
"blog"
;
    
public 
String getSql(Map<Integer, Object> parameter) {
        
BEGIN();
        
//SELECT("id,title,authername,date,content");
        
SELECT(
"*"
);
        
FROM(TABLE_NAME);
        
//注意这里这种传递参数方式,#{}与map中的key对应,而map中的key又是注解param设置的
        
WHERE(
"id = #{id}"
);
        
return 
SQL();
    
}
    
public 
String getAllSql() {
        
BEGIN();
        
SELECT(
"*"
);
        
FROM(TABLE_NAME);
        
return 
SQL();
    
}
    
public 
String getSqlByTitle(Map<String, Object> parameter) {
        
String title = (String) parameter.get(
"title"
);
        
BEGIN();
        
SELECT(
"*"
);
        
FROM(TABLE_NAME);
        
if 
(title != 
null
)
            
WHERE(
" title like #{title}"
);
        
return 
SQL();
    
}
    
public 
String insertSql() {
        
BEGIN();
        
INSERT_INTO(TABLE_NAME);
        
VALUES(
"title"
"#{title}"
);
        
//  VALUES("title", "#{tt.title}");
        
//这里是传递一个Blog对象的,如果是利用上面tt.方式,则必须利用Param来设置别名
        
VALUES(
"date"
"#{date}"
);
        
VALUES(
"authername"
"#{authername}"
);
        
VALUES(
"content"
"#{content}"
);
        
return 
SQL();
    
}
    
public 
String deleteSql() {
        
BEGIN();
        
DELETE_FROM(TABLE_NAME);
        
WHERE(
"id = #{id}"
);
        
return 
SQL();
    
}
    
public 
String updateSql() {
        
BEGIN();
        
UPDATE(TABLE_NAME);
        
SET(
"content = #{content}"
);
        
WHERE(
"id = #{id}"
);
        
return 
SQL();
    
}
}

 

注意由于在映射器接口中调用了@ResultMap,该注解内容是SQL配置文件ResultMap的ID,它是允许访问SQL配置文件中的ResultMap,则需要在相应的SQL配置相应ResultMap,然后再在主配置文件加上该SQL配置的Mapper路径。并且该SQL配置文件的namespace必须与使用@ResultMap的映射器接口的全限定相同。Blog.xml如下。

1
2
3
4
5
6
7
8
9
10
11
12
<?
xml 
version
=
"1.0" 
encoding
=
"UTF-8"
?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<
mapper 
namespace
=
"com.whut.inter.IBlogDAO"
>
   
<
resultMap 
type
=
"Blog" 
id
=
"sqlBlogsMap"
>
      
<
id 
property
=
"id" 
column
=
"id"
/>
      
<
result 
property
=
"title" 
column
=
"title"
/>
      
<
result 
property
=
"authername" 
column
=
"authername"
/>
      
<
result 
property
=
"date" 
column
=
"date"
/>
      
<
result 
property
=
"content" 
column
=
"content"
/>
   
</
resultMap
>
</
mapper
>

再在主配置文件mybatis-config.xml加入一句mapper。

1
2
3
<
mappers
>
        
<
mapper 
resource
=
"com/whut/model/Blog.xml"
/>
</
mappers
>

 

测试类

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package 
com.whut.test;
import 
java.io.IOException;
import 
java.io.Reader;
import 
java.util.List;
import 
org.apache.ibatis.io.Resources;
import 
org.apache.ibatis.session.SqlSession;
import 
org.apache.ibatis.session.SqlSessionFactory;
import 
org.apache.ibatis.session.SqlSessionFactoryBuilder;
import 
com.whut.inter.IBlogDAO;
import 
com.whut.model.Blog;
/**
 
* 注意这里是一种利用SqlBuilder以及多种设置来注解使用
 
* @author zxl
 
*
 
*/
public 
class 
TestBlog {
    
private 
static 
SqlSessionFactory sqlSessionFactory;
    
private 
static 
Reader reader;
    
static 
{
        
try 
{
            
Reader reader = Resources.getResourceAsReader(
"mybatic-config.xml"
);
            
sqlSessionFactory = 
new 
SqlSessionFactoryBuilder().build(reader);
            
// 由于使用了注解,所以在主配置文件没有mapper,需要在代码里显示注册该mapper接口
            
//sqlSessionFactory.getConfiguration().addMapper(IBlogDAO.class);
        
catch 
(IOException e) {
            
e.printStackTrace();
        
}
    
}
                                                                                                                           
    
public 
static 
void 
main(String[] args) {
        
//testOneBlog();
        
//testAllBlog();
        
//testBlogByTitle();
        
//testAddBlog();
        
//testDeleteBlog();
                                                                                                                               
        
testUpdateBlog();
    
}
                                                                                                                           
    
public 
static 
void 
testOneBlog()
    
{
        
SqlSession session=sqlSessionFactory.openSession();
        
try
{
            
IBlogDAO dao=session.getMapper(IBlogDAO.
class
);
            
Blog  blog=dao.getBlog(
2
);
            
System.out.println(blog.getId()+
"\t"
+blog.getAuthername()+
"\t"
+blog.getTitle());
        
}
finally
{
            
session.close();
        
}
                                                                                                                               
    
}
    
public 
static 
void 
testAllBlog()
    
{
        
SqlSession session=sqlSessionFactory.openSession();
        
try
{
            
IBlogDAO dao=session.getMapper(IBlogDAO.
class
);
            
List<Blog>  blogs=dao.getAllBlog();
            
System.out.println(
"编号\t作者\t标题"
);
            
for
(Blog blog:blogs)
            
System.out.println(blog.getId()+
"\t"
+blog.getAuthername()+
"\t"
+blog.getTitle());
        
}
finally
{
            
session.close();
        
}
    
}
    
public 
static 
void 
testBlogByTitle()
    
{
        
SqlSession session=sqlSessionFactory.openSession();
        
try
{
            
IBlogDAO dao=session.getMapper(IBlogDAO.
class
);
            
List<Blog>  blogs=dao.getBlogByTitle(
"%word%"
);
            
System.out.println(
"编号\t作者\t标题"
);
            
for
(Blog blog:blogs)
            
System.out.println(blog.getId()+
"\t"
+blog.getAuthername()+
"\t"
+blog.getTitle());
        
}
finally
{
            
session.close();
        
}
    
}
                                                                                                                           
    
public 
static 
void 
testAddBlog()
    
{
        
SqlSession session=sqlSessionFactory.openSession();
        
Blog blog=
new 
Blog();
        
blog.setTitle(
"chuntian"
);
        
blog.setAuthername(
"xiaohua"
);
        
blog.setDate(
"2013/12/25"
);
        
blog.setContent(
"bushuangyayya"
);
        
try
{
            
IBlogDAO dao=session.getMapper(IBlogDAO.
class
);
            
dao.insertBlog(blog);
            
session.commit();
        
}
finally
{
            
session.close();
        
}
    
}
                                                                                                                           
    
public 
static 
void 
testDeleteBlog()
    
{
        
SqlSession session=sqlSessionFactory.openSession();
        
try
{
            
IBlogDAO dao=session.getMapper(IBlogDAO.
class
);
            
dao.deleteBlog(
5
);
            
session.commit();
        
}
finally
{
            
session.close();
        
}
    
}
                                                                                                                           
    
public 
static 
void 
testUpdateBlog()
    
{
        
SqlSession session=sqlSessionFactory.openSession();
        
Blog blog=
new 
Blog();
        
blog.setId(
6
);
        
blog.setTitle(
"daxuexiaoyuan"
);
        
blog.setAuthername(
"xiaohua"
);
        
blog.setDate(
"2013/2/25"
);
        
blog.setContent(
"冷死了"
);
        
try
{
            
IBlogDAO dao=session.getMapper(IBlogDAO.
class
);
            
dao.updateBlog(blog);
            
session.commit();
        
}
finally
{
            
session.close();
        
}
    
}
}

 

注意事项:

1) 在利用注解配置映射器接口的时候,必须要通过

sqlSessionFactory.getConfiguration().addMapper(IBlogDAO.class);来对给映射器接口注册,如果映射器接口中使用了@ResultMap注解,则由于已经在mybatis-config.xml配置了Mapper,则就不需要再次在代码中添加mapper。

2)当方法有多个参数的时候,为了与SQL语句中的#{}对应,一般可以使用@Param("")来为每个参数命别名,使得该别名与#{}对应。当参数只有一个的时候,不需要别名。

3 在进行更新删除添加的时候,如果传递的是一个实体对象,则SQL可以直接使用实体的属性。

4)映射器接口调用SqlBuilder中的方法,都是将参数转换为Map中的key,可以在SqlBuilder的方法中利用Map来获取传递的参数值,进而进行逻辑操作判断。

5)注解中对于返回多条记录的查询可以直接利用@Results和@Result来配置映射,或者利用@ResultMap来调用SQL配置文件中的ResultMap。

 

--------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(1)官方开发文档:http://ibatis.apache.org/docs/dotnet/datamapper/ch03s09.html

<isGreaterThan prepend="AND" property="bo.lastUpdatedBy" compareValue="0">

<![CDATA[(

LAST_UPDATED_BY=#bo.lastUpdatedBy:NUMERIC#

)]]>

</isGreaterThan>

在ibatis中,该属性用于判断传入的值是否大于0

 

<isNotNull prepend="AND" property="bo.lastUpdateDate" >

<![CDATA[(

LAST_UPDATE_DATE=#bo.lastUpdateDate:TIMESTAMP#

)]]>

</isNotNull>

在ibatis中,该属性用于判断传入的值是否为空

 

 

IBATIS动态查询语句

<!-- 在ibatis中使用安全的拼接语句,动态查询 ibatis比JDBC的优势之一,安全高效说明文字在注释中 --> <select id="selectA

<!--

在ibatis中使用安全的拼接语句,动态查询

ibatis比JDBC的优势之一,安全高效

说明文字在注释中

-->

 

 

<select id="selectAllProducts" parameterClass="Product" resultMap="ProductResult">

select id,note from Product

<dynamic prepend="WHERE">

<!-- isNotNull判断参数是否存在,Integer类型 -->

<isNotNull property="id">

<!-- isGreaterThan判断参数是否大于compareValue,isGreaterEquals是大于等于 -->

<isGreaterThan prepend=" and " property="id" compareValue="0">

id = #id#

</isGreaterThan>

</isNotNull>

<!-- isNotEmpty判断字串不为空,isEmpty可以判断字串为空 -->

<isNotEmpty prepend=" and " property="note">

<!-- 模糊查询不能用#,#在是用prepareStatement的?插入参数,$是文本替换 -->

note like '%$note$%'

</isNotEmpty>

</dynamic>

</select>

 

用Map传参数

 

<select id="selectAllProducts" parameterClass="java.util.HashMap" resultMap="ProductResult">

select id,note from Product

<dynamic prepend="WHERE">

<!-- isPropertyAvailable判断属性是否有效 -->

<isPropertyAvailable property="id">

<isNotNull property="id">

<!-- isLessThan判断参数是否小于compareValue,isLessEquals是小于等于 -->

<isLessThan prepend=" and " property="id" compareValue="10">

id = #id#

</isLessThan>

</isNotNull>

</isPropertyAvailable>

</dynamic>

</select>

<!--------------------------------------------------------------------几个常用属性-->

 

<isPropertyAvailable> 属性是存在

<isNotPropertyAvailable> 属性不存在

<isNull> 属性值是null

<isEmpty> 判断Collection.size<1或String.length()<1

<isEqual> 等于

<isNotEqual> 不等于

<isGreaterThan> 大于

<isGreaterEqual> 大于等于

<isLessThan> 小于

<isLessEqual> 小于等于

ibatis中使用安全的拼接语句,动态查询,大于、小于、等于

2012-11-26 17:38:13| 分类: 默认分类 |举报|字号 订阅

在ibatis中使用安全的拼接语句,动态查询
ibatis比JDBC的优势之一,安全高效
说明文字在注释中

<select id="selectAllProducts" parameterClass="Product" resultMap="ProductResult">

select id,note from Product
<dynamic prepend="WHERE">
<!-- isNotNull判断参数是否存在,Integer类型 -->
<isNotNull property="id">
<!-- isGreaterThan判断参数是否大于compareValue,isGreaterEquals是大于等于 -->
<isGreaterThan prepend=" and " property="id" compareValue="0">
id = #id#
</isGreaterThan>
</isNotNull>
<!-- isNotEmpty判断字串不为空,isEmpty可以判断字串为空 -->
<isNotEmpty prepend=" and " property="note">
<!-- 模糊查询不能用#,#在是用prepareStatement的?插入参数,$是文本替换 -->
note like '%$note$%'
</isNotEmpty>
</dynamic>
</select>
用Map传参数
<select id="selectAllProducts" parameterClass="java.util.HashMap" resultMap="ProductResult">
select id,note from Product
<dynamic prepend="WHERE">
<!-- isPropertyAvailable判断属性是否有效 -->
<isPropertyAvailable property="id">
<isNotNull property="id">
<!-- isLessThan判断参数是否小于compareValue,isLessEquals是小于等于 -->
<isLessThan prepend=" and " property="id" compareValue="10">
id = #id#
</isLessThan>
</isNotNull>
</isPropertyAvailable>
</dynamic>
</select>
/*动态SQL的参数有

属性关键字

含义
<isEqual>
如果参数相等于值则查询条件有效。
<isNotEqual>
如果参数不等于值则查询条件有效。
<isGreaterThan>
如果参数大于值则查询条件有效。
<isGreaterEqual>
如果参数等于值则查询条件有效。
<isLessEqual>
如果参数小于值则查询条件有效。如下所示:

<isLessEqual prepend = ”AND” property = ”age” compareValue = ”18” >

ADOLESCENT = ‘TRUE’

</isLessEqual>

<isPropertyAvailable>
如果参数有使用则查询条件有效。
<isNotPropertyAvailable>
如果参数没有使用则查询条件有效。
<isNull>
如果参数为NULL则查询条件有效。
<isNotNull>
如果参数不为NULL则查询条件有效。
<isEmpty>
如果参数为空则查询条件有效。
<isNotEmpty>
如果参数不为空则查询条件有效。参数的数据类型为Collection、String 时参数不为NULL或“”。如下所示:

<isNotEmpty prepend=”AND” property=”firstName” >

FIRST_NAME=#firstName#

</isNotEmpty>

<isParameterPresent>
如果参数类不为NULL则查询条件有效。
<isNotParameterPresent>
Checks to see if the parameter object is not present (null). Example Usage:

<isNotParameterPresent prepend=”AND”>

EMPLOYEE_TYPE = ‘DEFAULT’

</isNotParameterPresent>

在复杂查询过程中,我们常常需要根据用户的选择决定查询条件,这里发生变化的并不只是SQL 中的参数,包括Select 语句中所包括的字段和限定条件,都可能发生变化。典型情况,如在一个复杂的组合查询页面,我们必须根据用户的选择和输入决定查询的条件组合。

一个典型的页面如下:

对于这个组合查询页面,根据用户选择填写的内容,我们应为其生成不同的查询语句。如用户没有填写任何信息即提交查询请求,我们应该返回所有记录:

Select * from t_user;
如用户只在页面上填写了姓名“Erica”,我们应该生成类似:
Select * from t_user where name like ‘%Erica%’ ;的SQL查询语句。
如用户只在页面上填写了地址“Beijing”,我们应该生成类似:
Select * from t_user where address like ‘%Beijing%”;的SQL。
而如果用户同时填写了姓名和地址(”Erica”&’Beijing’),则我们应生成类似:
Select * from t_user where name like ‘%Erica%’ and address like ‘%Beijing%”的SQL查询语句。

对于ibatis 这样需要预先指定SQL 语句的ORM 实现而言,传统的做法无非通过if-else 语句对输入参数加以判定,然后针对用户选择调用不同的statement 定义。对于上面这种简单的情况(两种查询条件的排列组合,共4 种情况)而言,statement 的重复定义工作已经让人不厌其烦,而对于动辄拥有七八个查询条件,乃至十几个查询条件

的排列组合而言,琐碎反复的statement定义实在让人不堪承受。

考虑到这个问题,ibatis引入了动态映射机制,即在statement定义中,根据不同的

查询参数,设定对应的SQL语句。
还是以上面的示例为例:
<select id="getUsers"
parameterClass="user"
resultMap="get-user-result">
select
id,
name,
sex
from t_user
<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="name">
(name like #name#)
</isNotEmpty>
<isNotEmpty prepend="AND" property="address">
(address like #address#)
</isNotEmpty>
</dynamic>
</select>
通过dynamic 节点,我们定义了一个动态的WHERE 子句。此WHERE 子句中将
可能包含两个针对name 和address 字段的判断条件。而这两个字段是否加入检索取决于用户所提供的查询条件(字段是否为空[isNotEmpty])。
对于一个典型的Web程序而言,我们通过HttpServletRequest获得表单中的字段名并将其设入查询参数,如:
user.setName(request.getParameter("name"));
user.setAddress(request.getParameter("address"));
sqlMap.queryForList("User.getUsers", user);
在执行queryForList("User.getUsers", user)时,ibatis 即根据配置文
件中设定的SQL动态生成规则,创建相应的SQL语句。
上面的示例中,我们通过判定节点isNotEmpty,指定了关于name 和address 属
性的动态规则:
<isNotEmpty prepend="AND" property="name">
(name like #name#)
</isNotEmpty>
这个节点对应的语义是,如果参数类的"name"属性非空(isNotEmpty,即非空
字符串””),则在生成的SQL Where字句中包括判定条件(name like #name#),其
中#name#将以参数类的name属性值填充。
Address属性的判定生成与name属性完全相同,这里就不再赘述。
这样,我们通过在statement 定义中引入dynamic 节点,很简单的实现了SQL 判定子句的动态生成,对于复杂的组合查询而言,这将带来极大的便利。判定节点的定义可以非常灵活,我们甚至可以使用嵌套的判定节点来实现复杂的动态映射,如:
<isNotEmpty prepend="AND" property="name">
( name=#name#
<isNotEmpty prepend="AND" property="address">
address=#address#
</isNotEmpty>
)
</isNotEmpty>
这段定义规定,只有用户提供了姓名信息时,才能结合地址数据进行查询(如果只提供地址数据,而将姓名信息忽略,将依然被视为全检索)。Dynamic节点和判定节点中的prepend属性,指明了本节点中定义的SQL子句在
主体SQL中出现时的前缀。如:

<dynamic prepend="WHERE">

<isNotEmpty prepend="AND" property="name">
(name like #name#)
</isNotEmpty>
<isNotEmpty prepend="AND" property="address">
(address like #address#)
</isNotEmpty>
</dynamic>

假设"name"属性的值为“Erica”, "address"属性的值为“Beijing”,则会生成类似下面的SQL子句(实际运行期将生成带占位符的PreparedStatement,之后再为其填充数据):

WHERE (name like ‘Beijing’) AND (address like ‘Beijing’)

其中WHERE 之后的语句是在dynamic 节点中所定义,因此以dynamic 节点的prepend设置("WHERE")作为前缀,而其中的”AND”,实际上是address属性所对应的isNotEmpty节点的prepend设定,它引领了对应节点中定义的SQL子句。至于name属性对应的isNotEmpty节点,由于ibatis会自动判定是否需要追加prepend前缀,这里(name like #name#)是WHERE 子句中的第一个条件子句,无需AND 前缀,所以自动省略。

判定节点并非仅限于isNotEmpty,ibatis中提供了丰富的判定定义功能。判定节点分两类:

? 一元判定

一元判定是针对属性值本身的判定,如属性是否为NULL,是否为空值等。
上面示例中isNotEmpty就是典型的一元判定。

一元判定节点有:

节点名 描述

<isPropertyAvailable> 参数类中是否提供了此属性
<isNotPropertyAvailable> 与<isPropertyAvailable>相反
<isNull> 属性值是否为NULL
<isNotNull> 与<isNull>相反
<isEmpty> 如果属性为Collection或者String,其size是否<1,如果非以上两种类型,则通过String.valueOf(属性值)
获得其String类型的值后,判断其size是否<1<isNotEmpty> 与<isEmpty>相反。

? 二元判定

二元判定有两个判定参数,一是属性名,而是判定值,如
<isGreaterThan prepend="AND" property="age"
compareValue="18">
(age=#age#)
</isGreaterThan>
其中,property="age"指定了属性名”age”,compareValue=”18”指明了判定值为”18”。上面判定节点isGreaterThan 对应的语义是:如果age 属性大于18(compareValue),则在SQL中加入(age=#age#)条件。
二元判定节点有:
节点名 属性值与compareValues的关系
<isEqual> 相等。
<isNotEqual> 不等。
<isGreaterThan> 大于
<isGreaterEqual> 大于等于
<isLessThan> 小于
<isLessEqual> 小于等于

 

为了防止SQL注入,iBatis模糊查询时也要避免使用$$来进行传值。下面是三个不同数据库的ibatis的模糊查询传值。
mysql: select * from stu where name like concat('%',#name #,'%')
oracle: select * from stu where name like '%'||#name #||'%'
SQL Server:select * from stu where name like '%'+#name #+'%
如:
<!-- 用途:小二后台查询活动的数目 -->
<!-- 频率:1000/天 -->
<!-- 维护:刘飞 -->
<select id="countActivitySearch" resultClass="java.lang.Long" parameterClass="actDO">
<![CDATA[
select count(id) from activity
]]>
<dynamic prepend="WHERE">
<isNotNull prepend=" AND " property="name">
name LIKE CONCAT('%', #name#, '%')
</isNotNull>
<isNotNull prepend=" AND " property="itemId">
itemId = #itemId#
</isNotNull>
<isNotNull prepend=" AND " property="itemName">
itemName LIKE CONCAT('%', #itemName#, '%')
</isNotNull>
<isNotNull prepend=" AND " property="status">
status = #status#
</isNotNull>
<isNotNull prepend=" AND " property="actStatus">
actStatus = #actStatus#
</isNotNull>
<isNotNull prepend=" AND " property="domain">
domain LIKE CONCAT('%', #domain#, '%')
</isNotNull>
</dynamic>
</select>
<!-- 用途:小二后台查询活动的列表 -->
<!-- 频率:1000/天 -->
<!-- 维护:刘飞 -->
<select id="searchActivityForList" resultMap="actResult" parameterClass="actDO">
<![CDATA[
select * from activity
]]>
<dynamic prepend="WHERE">
<isNotNull prepend=" AND " property="name">
name LIKE CONCAT('%', #name#, '%')
</isNotNull>
<isNotNull prepend=" AND " property="itemId">
itemId = #itemId#
</isNotNull>
<isNotNull prepend=" AND " property="itemName">
itemName LIKE CONCAT('%', #itemName#, '%')
</isNotNull>
<isNotNull prepend=" AND " property="status">
status = #status#
</isNotNull>
<isNotNull prepend=" AND " property="actStatus">
actStatus = #actStatus#
</isNotNull>
<isNotNull prepend=" AND " property="domain">
domain LIKE CONCAT('%', #domain#, '%')
</isNotNull>
</dynamic>
<![CDATA[
order by starttime desc, createtime desc
limit
#startRow#, #perPageSize#
]]>
</select>

 

IBatis模糊查詢

<!--

在ibatis中使用安全的拼接语句,动态查询
ibatis比JDBC的优势之一,安全高效
说明文字在注释中
-->

<select id="selectAllProducts" parameterClass="Product" resultMap="ProductResult">
select id,note from Product
<dynamic prepend="WHERE">
<!-- isNotNull判断参数是否存在,Integer类型 -->
<isNotNull property="id">
<!-- isGreaterThan判断参数是否大于compareValue,isGreaterEquals是大于等于 -->
<isGreaterThan prepend=" and " property="id" compareValue="0">
id = #id#
</isGreaterThan>
</isNotNull>
<!-- isNotEmpty判断字串不为空,isEmpty可以判断字串为空 -->
<isNotEmpty prepend=" and " property="note">
<!-- 模糊查询不能用#,#在是用prepareStatement的?插入参数,$是文本替换 -->
note like '%$note$%'
</isNotEmpty>
</dynamic>
</select>
用Map传参数
<select id="selectAllProducts" parameterClass="java.util.HashMap" resultMap="ProductResult">
select id,note from Product
<dynamic prepend="WHERE">
<!-- isPropertyAvailable判断属性是否有效 -->
<isPropertyAvailable property="id">
<isNotNull property="id">
<!-- isLessThan判断参数是否小于compareValue,isLessEquals是小于等于 -->
<isLessThan prepend=" and " property="id" compareValue="10">
id = #id#
</isLessThan>
</isNotNull>
</isPropertyAvailable>
</dynamic>
</select>
<!--------------------------------------------------------------------几个常用属性-->

<isPropertyAvailable> 属性是存在

<isNotPropertyAvailable> 属性不存在
<isNull> 属性值是null
<isEmpty> 判断Collection.size<1或String.length()<1
<isEqual> 等于
<isNotEqual> 不等于
<isGreaterThan> 大于
<isGreaterEqual> 大于等于
<isLessThan> 小于
<isLessEqual>

---------------------

Ibatis的动态查询使得数据操作变得非常的灵活,下次举出了常用的动态查询的属性信息: 

Ibatis配置信息 

Xml代码  
  1. <!-- Dynamic Sql -->  
  2.   <typeAlias alias="Student" type="com.ibatis.Student" />  
  3.     <typeAlias alias="StudentDTO" type="com.ibatis.StudentDTO" />  
  4.     <select id="dynamicGetStudent" parameterClass="StudentDTO"  
  5.         resultClass="Student">  
  6.         select *  
  7.         from student  
  8.         <dynamic prepend="WHERE">  
  9.             <isNotEqual prepend="AND" property="sid" compareValue="0">  
  10.                 sid = #sid#  
  11.             </isNotEqual>  
  12.               
  13.             <isNotNull prepend="AND" property="sname">  
  14.                 sname = #sname#  
  15.             </isNotNull>  
  16.         </dynamic>  
  17.         <dynamic prepend="order by">  
  18.             <isParameterPresent>  
  19.                 <isEqual prepend="order by" property="sort" compareValue="1">  
  20.                     sname desc,socre  
  21.                 </isEqual>  
  22.                   
  23.                 <isEqual prepend="order by" property="sort" compareValue="2">  
  24.                     sname asc,socre  
  25.                 </isEqual>  
  26.             </isParameterPresent>  
  27.         </dynamic>  
  28.     </select>  

Student的信息 

Java代码  
  1. package com.ibatis;  
  2.   
  3. import java.util.Date;  
  4.   
  5. public class Student {  
  6.     private int sid;  
  7.     private String sname;  
  8.     private String major;  
  9.     private Date birth;  
  10.     private int socre;  
  11.     public int getSid() {  
  12.         return sid;  
  13.     }  
  14.     public void setSid(int sid) {  
  15.         this.sid = sid;  
  16.     }  
  17.     public String getSname() {  
  18.         return sname;  
  19.     }  
  20.     public void setSname(String sname) {  
  21.         this.sname = sname;  
  22.     }  
  23.     public String getMajor() {  
  24.         return major;  
  25.     }  
  26.     public void setMajor(String major) {  
  27.         this.major = major;  
  28.     }  
  29.     public Date getBirth() {  
  30.         return birth;  
  31.     }  
  32.     public void setBirth(Date birth) {  
  33.         this.birth = birth;  
  34.     }  
  35.     public int getSocre() {  
  36.         return socre;  
  37.     }  
  38.     public void setSocre(int socre) {  
  39.         this.socre = socre;  
  40.     }  
  41.       
  42.     @Override  
  43.     public String toString() {  
  44.         String content = "Sid="+this.sid+"\t"+"Sname="+this.sname+"\t"+this.birth.toLocaleString();  
  45.         return content;  
  46.     }  
  47.       
  48. }  

StudentDTO的信息 

Java代码  
  1. package com.ibatis;  
  2.   
  3. import java.util.Date;  
  4.   
  5. public class StudentDTO {  
  6.     private int sid;  
  7.     private String sname;  
  8.     private String major;  
  9.     private Date birth;  
  10.     private int socre;  
  11.     private int sort;  
  12.     public int getSort() {  
  13.         return sort;  
  14.     }  
  15.     public void setSort(int sort) {  
  16.         this.sort = sort;  
  17.     }  
  18.     public int getSid() {  
  19.         return sid;  
  20.     }  
  21.     public void setSid(int sid) {  
  22.         this.sid = sid;  
  23.     }  
  24.     public String getSname() {  
  25.         return sname;  
  26.     }  
  27.     public void setSname(String sname) {  
  28.         this.sname = sname;  
  29.     }  
  30.     public String getMajor() {  
  31.         return major;  
  32.     }  
  33.     public void setMajor(String major) {  
  34.         this.major = major;  
  35.     }  
  36.     public Date getBirth() {  
  37.         return birth;  
  38.     }  
  39.     public void setBirth(Date birth) {  
  40.         this.birth = birth;  
  41.     }  
  42.     public int getSocre() {  
  43.         return socre;  
  44.     }  
  45.     public void setSocre(int socre) {  
  46.         this.socre = socre;  
  47.     }  
  48.       
  49.     @Override  
  50.     public String toString() {  
  51.         String content = "Sid="+this.sid+"\t"+"Sname="+this.sname+"\t"+this.birth.toLocaleString();  
  52.         return content;  
  53.     }  
  54.       
  55. }  

Java中的调用信息 

Java代码  
  1. @SuppressWarnings("unchecked")  
  2.     public static void main(String[] args) {  
  3.         List<Student> list = dao.dynamicGetStudent(studentDTO);  
  4.         for(Student student : list){  
  5.             System.out.println("name:"+student.getSname());  
  6.         }  
  7.         System.out.println("size:"+list.size());  
  8.     }  
  9. @Override  
  10.     public List dynamicGetStudent(StudentDTO studentDTO) {  
  11.         List result = null;  
  12.         try {  
  13.             result = sqlMapClient.queryForList("dynamicGetStudent",studentDTO);  
  14.         } catch (SQLException e) {  
  15.             // TODO Auto-generated catch block  
  16.             e.printStackTrace();  
  17.         }  
  18.         return result;  
  19.     }  

动态查询中的常用属性: 

 

属性关键字 含义
<isEqual> 如果参数相等于值则查询条件有效
<isNotEqual> 如果参数不等于值则查询条件有效
<isGreaterThan> 如果参数大于值则查询条件有效
<isGreaterEqual> 如果参数等于值则查询条件有效
<isLessEqual> 如果参数小于值则查询条件有效。如下所示:<isLessEqual prepend = ”AND” property = ”age” compareValue = ”18” >ADOLESCENT = ‘TRUE’</isLessEqual>
<isPropertyAvailable> 如果参数有使用则查询条件有效。
<isNotPropertyAvailable> 如果参数没有使用则查询条件有效
<isNull> 如果参数为NULL则查询条件有效
<isNotNull> 如果参数不为NULL则查询条件有效
<isEmpty> 如果参数为空则查询条件有效
<isNotEmpty> 如果参数不为空则查询条件有效
<isParameterPresent> 如果参数类不为NULL则查询条件有效
<isNotParameterPresent> Checks to see if the parameter object is not present (null). Example Usage

转载于:https://www.cnblogs.com/fx2008/p/4039653.html

你可能感兴趣的文章
4 Values whose Sum is 0 (二分+排序)
查看>>
netty
查看>>
类型对照表
查看>>
读书笔记之:Linux程序设计(第4版)(ch1-7)
查看>>
JS事件循环,MACRO TASK,MICRO TASK
查看>>
设计一个Roguelike-RPG小游戏
查看>>
非常不错的js 屏蔽类加验证类
查看>>
sencha touch 2中list如何动态添加或移除一个button
查看>>
lsjORM ----让开发变得更加快捷(二)
查看>>
iOS开发-iOS8地理位置定位
查看>>
struts2基于注解配置action
查看>>
原生爬虫(爬取熊猫直播人气主播排名)
查看>>
Resharp警告(去掉VS自动生成事件函数的警告)
查看>>
函数式编程初识篇
查看>>
如何解决vim乱码【转载】
查看>>
bzoj 4241 历史研究——分块(区间加权众数)
查看>>
上海第二天(面临着坐地铁)
查看>>
莫烦大大TensorFlow学习笔记(8)----优化器
查看>>
贝叶斯算法
查看>>
C++ 自定义控件的移植(将在其它程序中设计的自定义控件,移植到现在的系统中)...
查看>>