MyBatis: POOL

张天宇 on 2020-04-03

MyBatis中的连接池。

连接池

用于存储连接的一个容器,减少获取连接所消耗的时间。

容器其实就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到统一连接。该集合还必须实现队列的特征:先进先出。

MyBatis连接池

配置位置

主配置文件SqlMapConfig.xml中的dataSource标签,type表示使用何种连接池的方式。

Type取值

  • POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。

  • UNPOOLED:采用传统的获取连接的方式,虽然也实现javax.sql.DataSource接口,但是并没有使用池的思想。

  • JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样的。注意,如果不是Web或者Maven的war工程,是不能使用的。

MyBatis中的动态SQL语句

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

if标签的使用

如果这个时候我们有一个需求,就是根据传入的实体类,判断哪些属性不为空,并以此作为查询条件,那么我们就可以用到了if标签。

  1. 定义接口方法

    1
    List<User> findUserByCondition(User user);
  2. 配置映射文件

    1
    2
    3
    4
    5
    6
    <select id="findUserByCondition" resultType="top.tyzhang.domain.User" parameterType="top.tyzhang.domain.User">
    select * from userm where 1=1
    <if test="username!=null">
    and username=#{username}
    </if>
    </select>

    多个条件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <select id="findUserByCondition" resultType="top.tyzhang.domain.User" parameterType="top.tyzhang.domain.User">
    select * from userm where 1=1
    <if test="username!=null">
    and username=#{username}
    </if>
    <if test="birthday != null">
    and birthday = #{birthday}
    </if>
    </select>

    注意:这里加上 WHERE 1 =1 是防止所有条件都为空时拼接 SQL 语句出错。因为不加上 1 = 1 这个恒等条件的话,如果后面查询条件都没拼接成功,那么 SQL 语句最后会带有一个 WHERE 关键字而没有条件,不符合 SQL 语法。

    • 如果 test 有多个条件,那么必须使用 and 进行连接,而不能使用 Java 中的 && 运算符。
    • test 中的参数名称必须与实体类的属性保持一致,也就是和 #{参数符号} 保持一致。
    • 如果判断条件为字符串,那么除了判断是否为 null 外,最好也判断一下是否为空字符串,‘’ ,防止 SQL语句将其作为条件查询。
  3. 测试代码

    1
    2
    3
    4
    5
    User user=new User();
    user.setUsername("老王");
    List<User> users=userDao.findUserByCondition(user);
    for (User userq:users)
    System.out.println(userq);

where标签的使用

使用where标签优化WHERE 1 = 1

1
2
3
4
5
6
7
8
9
10
11
<select id="findUserByCondition" resultType="top.tyzhang.domain.User" parameterType="top.tyzhang.domain.User">
select * from userm
<where>
<if test="username!=null">
and username=#{username}
</if>
<if test="birthday != null">
and birthday = #{birthday}
</if>
</where>
</select>

foreach标签的使用

SELECT \* FROM user WHERE id IN(41,42,43);

QueryVo中存放一个List

1
2
3
4
5
6
7
8
9
10
<select id="findUserInIds" resultType="top.tyzhang.domain.User" parameterType="top.tyzhang.domain.QueryVo">
select * from userm
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>

测试

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void testFindInIds(){
QueryVo queryVo=new QueryVo();
List<Integer> integers=new ArrayList<Integer>();
integers.add(41);
integers.add(42);
integers.add(43);
queryVo.setIds(integers);
List<User> users=userDao.findUserInIds(queryVo);
for (User userq:users)
System.out.println(userq);
}

sql标签使用

定义sql语句

1
2
3
<sql id="defaultSql">
SELECT * FROM user
</sql>

引用

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 根据id集合查询用户 -->
<select id="listUsersByIds" parameterType="cn.ykf.pojo.QueryVo" resultMap="userMap">
<!-- 引用代码片段 -->
<include refid="defaultSql"></include>
<where>
<if test="ids != null and ids.size > 0">
<foreach collection="ids" open="AND id IN (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>

其他标签

CSDN

多表查询

一对多

以用户和账户为例子,一个用户可以有多个账户,一个账户只能属于一个用户。

建立Account的子类AccountUser实现(实际用的不多)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 创建用户表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 导入用户数据
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');
# 创建账户表,外键为uid,关联用户表的id
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`id` int(11) NOT NULL COMMENT '编号',
`uid` int(11) default NULL COMMENT '用户编号',
`money` double default NULL COMMENT '金额',
PRIMARY KEY (`id`),
KEY `FK_Reference_8` (`uid`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`uid`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 导入账户数据
insert into `account`(`id`,`uid`,`money`) values (1,46,1000),(2,45,1000),(3,46,2000);
1
2
3
4
5
6
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//...
}
1
2
3
4
5
6
7
public interface IAccountDao {
List<Account> findAll();
/**
* 查询所有账户,并且带有用户名称和地址信息
*/
List<AccountUser> findAllAccount();
}
1
2
3
4
5
public class AccountUser extends Account{
private String username;
private String address;
//...
}
1
2
3
4
<!--查询所有账户,并且带有用户名称和地址信息-->
<select id="findAllAccount" resultType="top.tyzhang.domain.AccountUser">
SELECT a.*, u.username, u.address from account a, userm u WHERE a.uid = u.id
</select>
1
2
3
4
5
6
@Test
public void findAllAccountUser() {
List<AccountUser> accountUsers = accountDao.findAllAccount();
for (AccountUser accountUser : accountUsers)
System.out.println(accountUser);
}
建立实体类关系的方式

findAll基础上改进

1
2
3
4
5
6
7
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
//...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<resultMap id="accountUserMap" type="top.tyzhang.domain.Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<association property="user" column="uid" javaType="top.tyzhang.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
<select id="findAll" resultMap="accountUserMap">
SELECT U.*, a.id AS aid, a.uid, a.money from account a, userm u WHERE a.uid = u.id;
</select>
1
2
3
4
5
6
7
8
@Test
public void findAll() {
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
System.out.println(account.getUser());
}
}

多对多

https://blog.csdn.net/a1092882580/article/details/104152566

JNDI

JNDI: Java Naming and Directory Interface是SUN公司推出的一套规范,属于JavaEE技术之一,目的是模仿Windows系统中的注册表。

WAR工程的配置

1
2
3
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jdbc/eesy_mybatis"></property>
</dataSource>

参考

https://blog.csdn.net/a1092882580/article/details/104086181