一、Mybatis 连接池
1. Mybatis中数据源分类
Mybatis将它自己的数据源分为三类:
UNPOOLED
,不使用连接池的数据源POOLED
,使用连接池的数据源JNDI
,使用 JNDI 实现的数据源
2. Mybatis中数据源的配置
<environments default="mysql">
<environment id="mysql">
<!--事务管理器-->
<transactionManager type="jdbc"/>
<!--连接池配置-->
<dataSource type="pooled">
<!--获取配置文件中的key对应的值 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
MyBatis在初始化时,解析此文件,根据<dataSource>
的 type 属性来创建相应类型的的数据源DataSource,即:
-
type="POOLED"
: MyBatis 会创建 Pooled DataSource 实例; -
type="UNPOOLED"
: MyBatis 会创建 Unpooled DataSource 实例; -
type="JNDI"
: MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用。
二、Mybatis动态SQL
1. <if>
<!--条件查询:id、name-->
<!--ognl表达式语言 Object-Graph Navigation Language-->
<!--mybatis获取对象的值就用到了ognl表达式。开源的项目。-->
<select id="findByCondition" parameterType="queryvo" resultType="com.zz.entity.User">
select * from user where 1=1
<!-- 条件判断 -->
<if test="user!= null and user.id != 0">
and id=#{user.id}
</if>
<if test="user!= null and user.username != null">
and username=#{user.username}
</if>
</select>
2. <where>
<!--条件查询:id、name-->
<select id="findByCondition" parameterType="queryvo" resultType="com.zz.entity.User">
select * from user
<where>
<!-- 条件判断 -->
<if test="user!= null and user.id != 0">
and id=#{user.id}
</if>
<if test="user!= null and user.username != null">
and username=#{user.username}
</if>
</where>
</select>
3. <foreach>
<!--条件查询:id、name-->
<select id="findByCondition" parameterType="queryvo" resultType="com.itheima.entity.User">
select * from user
<where>
<!-- 条件判断 -->
<if test="user!= null and user.id != 0">
and id=#{user.id}
</if>
<if test="user!= null and user.username != null">
and username=#{user.username}
</if>
<!-- 根据多个id查询,需要遍历条件 -->
<!--
SELECT * FROM USER WHERE 1=1 and id IN (1,2)
foreach 遍历集合
collection 要遍历的集合
item 临时变量存储当前遍历的集合的每一个元素
open 拼接sql的开始
close 拼接sql的结束
seperator 分隔符,连接遍历的每一个值
-->
<if test="ids!=null and ids.size()>0">
<foreach item="num" collection="ids" open="and id IN (" separator="," close=")">
#{num}
</foreach>
</if>
</where>
</select>
4. <include>
<!--定义通用的Sql片段-->
<sql id="selectUser">
select * from user
</sql>
<!--条件查询:id、name-->
<select id="findByCondition" parameterType="queryvo" resultType="user">
<!--引用Sql片段-->
<include refid="selectUser"></include>
<where>
<!-- 条件判断 -->
<if test="user!= null and user.id != 0">
and id=#{user.id}
</if>
<if test="user!= null and user.username != null">
and username=#{user.username}
</if>
</where>
</select>
注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如:<include refid="namespace.sql 片段"/>
三、Mybatis的多表关联查询
1. 一对一
实体类:
public class Account {
private int accountId;
private double money;
//账户与用户一对一
private User user;
...
}
public class User {
private int id;
private String username;
private String sex;
private String address;
private Date birthday;
//一个用户有多个账户
private List<Account> accounts;
...
}
AccountDao
接口:
public interface AccountDao {
List<Account> findAccountByUserId(int userId);
}
AccountDao.xml
:
<mapper namespace="com.zz.dao.AccountDao">
<resultMap id="userResultMap" type="account">
<!--1.先封装账户信息-->
<id property="accountId" column="accountId" />
<result property="money" column="money"/>
<!--2.封装用户信息-->
<!--
association 一对一关系配置。可以给Account的对象的user属性封装数据
property 要封装的对象的属性
javaType 对象类型
column 外键字段(账户的用户id外键)
-->
<association property="user" javaType="com.zz.entity.User" column="uid">
<!--封装用户信息-->
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<result property="birthday" column="birthday"/>
</association>
</resultMap>
<!--查询(把账户、用户都通过连接查询查询出来)-->
<select id="findAccountByUserId" parameterType="int" resultMap="userResultMap">
SELECT a.*,u.* FROM account a INNER JOIN USER u ON a.uid=u.id where a.uid=#{userId}
</select>
</mapper>
2. 一对多
UserDao
接口:
public interface UserDao {
//查询全部用户,同时还要查询出用户对应的全部账户信息)
List<User> findAll();
}
UserDao.xml
:
<mapper namespace="com.zz.dao.UserDao">
<!--通过resultMap封装结果数据-->
<resultMap id="accountResultMap" type="user">
<!--1.封装用户信息-->
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<result property="birthday" column="birthday"/>
<!--2.封装账户集合-->
<!--
collection 一对多配置
property 集合属性
ofType 集合元素类型
javaType (可选)表示集合的类型:java.util.List
column (可选)表示用户的主键:id
-->
<collection property="accounts" ofType="com.zz.entity.Account" >
<id property="accountId" column="accountId" />
<result property="money" column="money"/>
</collection>
</resultMap>
<!--查询(把用户、用户的账户都通过关联查询查询出来)-->
<select id="findAll" resultMap="accountResultMap">
SELECT u.*,a.* FROM USER u LEFT JOIN account a ON a.uid=u.id
</select>
</mapper>
3. 多对多
多对多可以理解为双向一对多
四、常见SQL
1. 注解中判断某个字符串参数是否为null或者空字符串
<when>:
@Select({"<script>",
"select * from user_info where 1=1",
"<when test='name!=null and name!=\"\"'>",
"and name = #{name}",
"</when>",
"<when test='password!=null and password!=\"\"'>",
"and password= #{password}",
"</when>",
"</script>"})
public User selectByNamePassword(String name,String password);
<if>:
@Select({"<script>",
"select * from user_info where 1=1",
"<if test='name!=null and name!=\"\"'>",
"and name = #{name}",
"</if>",
"<if test='password!=null and password!=\"\"'>",
"and password= #{password}",
"</if>",
"</script>"})
public User selectByNamePassword(String name,String password);
2. Mybatis插入数据时获取自增的主键Id
- ServiceImpl
@Override
public void insertProject(String areaName, String project, String status) {
try {
// 查找areaId,未找到则插入area表中
Integer areaId = areaMapper.findAreaId(areaName);
if (areaId == null) {
Area area = new Area();
area.setAreaName(areaName);
area.setStatus(0);
areaMapper.insertArea(area);
// 获取主键
areaId = area.getAreaId();
}
projectMapper.insertProject(project, areaId, status);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 表AREA_T插入数据,获取自增主键 AreaId
* keyProperty: 主键实体类属性名 keyColumn: 主键表列名
*/
@Insert("insert into AREA_T(area_name,del_flag) values(#{areaName},#{status});")
@Options(useGeneratedKeys = true, keyProperty = "areaName", keyColumn = "area_name")
void insertArea(Area area);
注:现在不用注解即可,MyBatis插入area后,area的主键会被MyBatis返回并赋值,直接用get方法即可获取到主键ID,即使不是自增主键也可获取。