Mybatis的基础配置
一.基础配置
1.1xml配置环境
pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>day02_eesy_01mybatisCRUD</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
</project>
src/main/resources/MybatisConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbcConfig.properties"></properties>
<!--为该包下的类取别名,配置dao的时候不用写全类名了-->
<typeAliases>
<package name="com.itheima.domain"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"/>
</mappers>
</configuration>
1.2编写代码
dao接口
package com.itheima.dao;
import com.itheima.domain.User;
import java.util.List;
public interface IUserDao {
/**
* 查询所有操作
*/
List<User> findAll();
}
src/main/resources/对应的dao的路径/dao.xml
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--namespace绑定一个对应的mapper接口-->
<mapper namespace="com.itheima.dao.IUserDao">
<!--配置查询所有-->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
</mapper>
test文件
public class MybatisTest {
/**
* 入门案例
* @param args
*/
public static void main(String[] args) throws Exception {
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建一个SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
}
}
1.3.注解配置:
dao接口:
public interface IUserDao {
/**
* 查询所有操作
*/
@Select("select * from user")
List<User> findAll();
@Select("select * from user where id = #{em}")
User getUserById(int id);
@Select("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
}
mybatisConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的主配置文件-->
<configuration>
<!--配置环境-->
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED">
<!--配置连接池的四个基本信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件
如果是用注解来配置,此处应该使用class属性指定被注解的dao全限定类名
-->
<mappers>
<mapper class="com.itheima.dao.IUserDao"/>
</mappers>
</configuration>
二.Mybatis全局配置文件讲解
2.1全局配置文件的类容和顺序
Properties(属性):通过该标签来读取java配置信息(jdbc.properties)
Settings(全局参数设置):一般我们使用使用该标签来开启二级缓存和懒加载。
typeAliases(类型别名):在编写sql语句的时候不用在使用全类名了
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境信息集合)
-environment(单个环境信息)
–transactionManager(事务)
–dataSource(数据源)
mappers(映射器):该标签的作用是加载映射文件
2.2 详解
Properties标签
作用:引入外部资源文件
jdbcConfig.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=admin
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbcConfig.properties"></properties>
<typeAliases>
<package name="com.itheima.domain"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
</configuration>
settings标签
一般用于开启懒加载和二级缓存
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<!--开启缓存,还要再对应的dao.xml中开启-->
<setting name="cacheEnabled" value="true"/>
</settings>
typeAliases标签
作用:该标签是对po类进行别名设置,这样,在后面使用po类的时候就可以直接通过别名引用,而不需要通过po类的全限定名来引用。这样可以提高我们的开发效率。
mappers标签
作用:加载配置文件(xml,或者注解)
方法一:引入xml
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"/>
</mappers>
方法二:引入注解
<mappers>
<mapper class="com.itheima.dao.IUserDao"/>
</mappers>
方法三:引入整个包下的
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
三:映射文件
3.1:parameterType
第一种:简单类型
<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultType="user" >
select * from user where id = #{uid}
</select>
此时#{}内可以随意填写
第二种:pojo类型
<!--更新用户信息-->
<update id="updateUser" parameterType="user">
update user set username=#{username},address=#{address} where id=#{id}
</update>
此时#{}里面的必须和user内部的属性名对应
第三种:包装类
先创建一个包装类,包装user对象
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
<!--根据QueryVo的条件查询用户-->
<select id="findUserByVo" parameterType="com.itheima.domain.QueryVo" resultType="com.itheima.domain.User">
select * from user where username like #{user.username};
<!--注意这个user的名字不能瞎写,要和QueryVo里面的user属性同步,这个user属性里面才有username属性-->
</select>
注意:#{}和${}的区别
1.#{}表示占位符?,parameterType接收简单类型的参数时,里面的名称可以任意。
2.${}表示拼接符,parameterType接收简单类型的参数时,里面的名称必须是value
大家可以试试看下面两个的区别:原地址
SELECT * FROM #{tableName}
SELECT * FROM ${value}
在模糊查询中:
select * from user where username like #{lala};
<!--方法二: select * from user where username like '%${value}%';--><!--里面固定为value-->
3.2:resultType
resultType结果映射要求:需要查询结果的列名和映射的对象的属性名一致,这样才能映射成功。如果映射没成功也不会报错,只是映射结果中对象的相应属性没有值,为空。如果映射的列名和对象中的属性名全部不一致,那么映射的对象为空。如果在使用sql语句查询的时候给查询结果列设置了别名,则别名要和映射结果对象的属性名一致,这样才能保证映射成功。
第一种:简单类型
<select id="findUserCount" resultType="int">
select count(*) from user;
</select>
第二种:pojo类型
<!--查询用户-->
<select id="findUser" parameterType="int" resultType="com.itheima.domain.User">
select * from user where id=#{uid};
</select>
3.3:resultMap
作用:使用resultMap结果映射时,不需要查询出来的结果集的列名和映射结果对象的属性名相同,但是需要声明一个resultMap,手动的方式来对列名和对象属性进行映射。(或者可以在sql语句种取别名,是查询结果和pojo属性名字一致)
映射文件添加查询语句:
[id]:定义resultMap的唯一标识
[type]:定义该resultMap最终映射的pojo对象
[id标签]:映射结果集的唯一标识列,如果是多个字段联合唯一,则定义多个id标签
[result标签]:映射结果集的普通列
[column]:SQL查询的列名,如果列有别名,则该处填写别名
[property]:pojo对象的属性名。
user类:
public class User implements Serializable {
private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;
.....略
}
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="userMap" type="uSeR">
<!-- 主键字段的对应 -->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
3.4动态sql
3.4.1:if语句
dao.xml中
<!--根据条件查询-->
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user where 1=1
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
<!-- select * from user
<where>
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
</where>-->
</select>
这里有1=1或者where标签所以即使条件为null,WHERE后面也不会报错。
Test类中:
@Test
public void testFindByCondition(){
User u = new User();
u.setUserName("老王");
// u.setUserSex("女");
List<User> users = userDao.findUserByCondition(u);
for(User user : users){
System.out.println(user);
}
}
3.4.2:foreach语句
foreach用来遍历,遍历的对象可以是数组,也可以是集合。
相关属性:
Collection:collection属性的值有三个分别是list、array、map三种。
Open:前缀。
Close:后缀。
Separator:分隔符,表示迭代时每个元素之间以什么分隔。
Item:表示在迭代过程中每一个元素的别名。
Index:用一个变量名表示当前循环的索引位置。
<!--根据queryvo中的id集合实现查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
select * from user
<where>
<foreach collection="ids" item="uid" open="and id in (" separator=" or " close=")" >
#{uid}
</foreach>
</where>
</select>
QueryVo类:
public class QueryVo {
private User user;
private List<Integer> ids;
}
Test类中:
/**
* 测试foreach标签的使用
*/
@Test
public void testFindInIds(){
QueryVo queryVo = new QueryVo();
ArrayList<Integer> list = new ArrayList<>();
list.add(41);
list.add(42);
list.add(46);
queryVo.setIds(list);
List<User> users = userDao.findUserInIds(queryVo);
for(User user : users){
System.out.println(user);
}
}
四:x对x查询
背景:分别有account表和user表
一个user可以有多个账号。
一个账号只能对应一个user。
4.1:一对一查询
给账号查询user
- 思路一:创建一个类AccountUser继承Account,再定义user的字段,里面前面的方法进行封装,返回类型为AccountUser。
- 思路二:再在Account类中定义一个User属性。见下:
Account类:
public class Account implements Serializable {
private Integer ID;
private Integer uid;
private double money;
//从表实体应该包含一个主表实体的对象引用
private User user;
}
Test类:
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for(Account account : accounts){
System.out.println("-----------每一个account的信息-------------------");
System.out.println(account);
System.out.println(account.getUser());
}
}
Dao.xml
<!--定义封装的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.`money`,a.`uid` FROM account a,USER u WHERE a.`uid` = u.`id`
</select>
4.2:一对多查询
User类:
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//1对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;
}
dao.xml
<!--定义user的resultMap-->
<resultMap id="userAccountMap" type="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>
<collection property="accounts" ofType="account">
<id property="ID" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
SELECT u.* ,a.`ID` AS aid ,a.`money`,a.`uid` FROM USER u LEFT OUTER JOIN account a ON u.id = a.uid
</select>
Test类:
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println("----------每个用户的信息-----------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
4.3:多对多查询
背景:role(角色表),user_role表,一个角色可以有多个人,一个人叶有多个角色。比如:演员(角色):胡歌,黄渤。胡歌(人):演员,歌手。
这样以看又变成了一对多了。。。。。略
五:懒加载
sql语句不一次性加载,用到了我就去执行,不然不执行。
MybatisConfig.xml中开启懒加载
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
我执行下面的语句:
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println("----------每个用户的信息-----------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
没开启:
开启:
六:缓存
6.1: 开启缓存
mybatisConfig.xml
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
6.2:案例分析
第一种:同一个sqlSession开启的dao对象:
只查询了一次,共用缓存
第二种:两个sqlSession开启的dao对象
查询了两次,说明不同的sqlSession不共用缓存
第三种:当有缓存另一个来修改的时候
@Test
public void testMyIdeal(){
User user1 = userDao.findById(49);
System.out.println("userDao1更新前的user是"+user1);
User user2 = userDao2.findById(49);
System.out.println("userDao2更新前的user是"+user2);
//更新user对象
User userNew = new User();
userNew.setUsername("马云");
userNew.setId(49);
userNew.setAddress("北京");
userDao2.updateUser(userNew);
User user2new = userDao2.findById(49);
System.out.println("更新后userDao2的user是:" + user2new);
System.out.println("更新后userDao1的user是"+user1);
//查询查看
User user3 = userDao.findById(49);
System.out.println(user3);
}
若加上update的话,那么相当于六次结果,但只有4个查询语句。
session1在刷新之后重新打印user对象发现还是没修改前的样子。说明在session1有缓存的情况下,session2修个session1缓存中的那个对象,session1 会出现误读的情况,并且重新查询session1还是呆呆的以为自己的缓存仍然是好的。但是session2继续查询的话会执行查询语句,说明更新后会刷新当前session的缓存。
本文地址:https://blog.csdn.net/qq_45595546/article/details/107484203