Mybatis的dao实现类的执行过程
-
PreparedStatement对象它的执行方法
-
execute:它能执行CRUD中的任意-种语句。它的返回值是一个boolean类型,表示是否有结果集。有结果集是true,没有结果集是fasle
-
executeUpdate:它只能执行CUD语句,查询语句无法执行。他的返回值是影响数据库记录的行数
-
executeQuery:它只能执行SELECT语句,无法执行增删改。执行结果封装的结果集ResultSet对象
-
-
分析编写dao实现类Mybatis的执行过程:
分析代理dao的执行过程
Mybatis 连接池与事务深入
-
在 Mybatis 中也有连接池技术,它采用的是自己的连接池技术。在
Mybatis
的mybatis-config.xml
配置文件中,通过<dataSource type="pooled">
来实现 Mybatis 中连接池的配置。 -
在 Mybatis 中我们将它的数据源 dataSource 分为以下几类:
UNPOOLED
:不使用连接池的数据源,采用传统的javax. sql. DataSource规范中的连接池,mybatis中有针对规范的实现POOLED
:使用连接池的数据源,采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource
接口,但是并没有使用池的思想。JNDI
: 使用 JNDI 实现的数据源,采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样 -
在这三种数据源中,我们一般采用的是
POOLED
数据源(很多时候我们所说的数据源就是为了更好的管理数据
库连接,也就是我们所说的连接池技术)。 -
MyBatis 内部分别定义了实现了
java.sql.DataSource
接口的UnpooledDataSource
,PooledDataSource
类来表示UNPOOLED
、POOLED
类型的数据源。PooledDataSource
和UnpooledDataSource
都实现了java.sqlDataSource
接口。并且PooledDataSource
持有一个UnpooledDataSource
的引用 。当PooledDataSource
需要创建java.sql.Connection
实例对象时。还是通过UnpooledDataSource
来创建,PooledDataSource
只是提供一种缓存连接池机制。
-
Mybatis 中
DataSource
的存取- MyBatis 是通过工厂模式来创建数据源 DataSource 对象的, MyBatis 定义了抽象的工厂接口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源DataSource。
- MyBatis 是通过工厂模式来创建数据源 DataSource 对象的, MyBatis 定义了抽象的工厂接口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源DataSource。
- Mybatis 中事务的提交方式,本质上就是调用 JDBC 的
setAutoCommit()
来实现事务控制 - 通过源码分析,设置
session = factory.openSession(true)
即可以改成自动提交,
- 此时事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为 false再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。
Mybatis 的动态 SQL 语句
-
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 name 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到
-
示例代码:
-
持久层 Dao 接口:
/**
* 根据用户信息,查询用户列表
*/
List<User> queryByUser(User user);
- 持久层 Dao 映射配置:
<select id="queryByUser" resultMap="userMap">
select * from user
where 1 = 1
<if test="name != null and name.trim!=''">
and name = #{name}
</if>
<if test="uAddress != null and uAddress.trim!=''">
and address like concat('%',#{uAddress},'%')
</if>
</select>
- 为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
- 代码示例:
- 持久层 Dao 映射配置:
<select id="queryByUser" resultMap="userMap">
select * from user
<where>
<if test="name != null and name.trim!=''">
and name = #{name}
</if>
<if test="uAddress != null and uAddress.trim!=''">
and address like concat('%',#{uAddress},'%')
</if>
</where>
</select>
-
当查询的条件为集合时需要用到 foreach 标签
-
代码示例:
-
持久层 Dao 接口:
/**
* 根据多个用户id,查询用户列表,ids为集合,没有set,get方法,mybatis中需要用if,所以需要用到@Param注解
*/
List<User> queryByListId(@Param("ids")List<Integer> ids);
- 持久层 Dao 映射 配置:
<select id="queryByListId" resultMap="userMap">
select * from user
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
-
SQL 语句解析:
-
select * from user where id in (?)
<foreach>
标签用于遍历集合,它的属性:collection
:代表要遍历的集合元素,注意编写时不要写#{}open
:代表语句的开始部分close
:代表结束部分item
:代表遍历集合的每个元素,生成的变量名sperator
:代表分隔符
-
-
测试类:
@Test
public void queryByListIdTest() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<User> userList = userDao.queryByListId(list);
userList.stream().forEach(System.out::println);
}
-
Sql 中可将重复的 sql 提取出来,使用时用
include
引用即可,最终达到 sql 重用的目的。 -
示例代码:
-
定义代码片段:
<!-- 抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>
- 引用代码片段:
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="user">
<include refid="defaultSql"></include>
</select>
Mybatis 多表查询之一对多
- 因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询:
- Account 实体:
/**
* 账户实体类
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//从表实体应该包含一个主表实体的对象引用
private User user;
}
- User 实体:
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
}
- AccountDao 接口中的方法:
/**
* 账户的持久层接口
*/
public interface AccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<Account> findAll();
}
- AccountDao.xml 文件:
<mapper namespace="com.zhou.dao.AccountDao">
<!-- 定义封装account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容-->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id
</select>
</mapper>
-
用户信息和他的账户信息为一对多关系:
-
User 实体类:
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;
}
- 用户持久层 Dao 接口 中加入查询方法:
/**
* 查询所有用户,同时获取出每个用户下的所有账户信息
*/
List<User> findAll();
- 用户持久层 Dao 映射文件 配置:
<resultMap id="userMap" type="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
<!-- collection 是用于建立一对多中集合属性的对应关系ofType 用于指定集合元素的数据类型 -->
<collection property="accounts" ofType="account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<select id="queryAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left join account a on u.id =a.uid
</select>
- 测试方法:
@Test
public void queryAllTests() {
List<User> users = userDao.queryAll();
for(User user : users) {
System.out.println(user);
System.out.println(user.getAccounts());
}
}
Mybatis 多表查询之多对多
-
用户与角色的多对多关系模型如下:
-
实现查询所有对象并且加载它所分配的用户信息:
-
Role实体类:
@ToString
@Data
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
//多对多的关系映射:一个角色可以赋予多个用户
private List<User> users;
}
- 编写 Role 持久层 接口:
public interface IRoleDao {
/**
* 查询所有角色
*/
List<Role> queryRoleAll();
}
- 编写映射文件:
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
<select id="queryRoleAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
left join user_role ur on r.id = ur.rid
left join user u on u.id = ur.uid
</select>
- 编写测试类
@Test
public void queryRoleAllTest() {
List<Role> roles = roleDao.queryRoleAll();
roles.stream().forEach(System.out::println);
}