02-MyBatis相关

一、第一个mybatis程序

思路流程:搭建环境–>导入Mybatis—>编写代码—>测试

1.搭建实验数据库mybatis,新建一张usr表

在这里插入图片描述

2.在pom.xml导入依赖

<dependencies>
    <!--mybatis相关-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
    <!--mysql相关-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--配置Maven静态资源过滤问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

2.写对应数据库的实体类com.tong.pojo包下的User

@Data
public class User {
 
  private int id;  //id
  private String name;  //姓名
  private String pwd;  //密码
 
 } 

3.创建包com.tong.dao中写UserMapper的接口

public interface UserMapper {
    //查询所有
   	public List<User> selectUser();
}

4.在com.tong.dao下写对应的UserMapper.xml

<?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.tong.dao.UserMapper">
     <select id="selectUser" resultType="com.tong.pojo.User">
        select * from user
     </select>
</mapper>

5.在resources目录下新建mybatis-config.xml配置文件,编写mybatis的配置

<?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>

    <!--自定义别名,这样在mapper.xml中的这样写resultType="Student
    如果没有自定义别名,在mapper.xml 中要写完包名 resultType="com.kuang.pojo.Student
    -->
    <typeAliases>
        <package name="com.tong.pojo" />
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--注册映射文件 1-->
   <!-- <mappers>
        <mapper class="com.tong.dao.UserMapper"/>
    </mappers>-->

    <!--注册映射文件 2-->
    <mappers>
        <mapper resource="com/tong/dao/UserMapper.xml"/>
    </mappers>

</configuration>

6.写一个测试类

  @Test
    public void test() throws IOException {

     //读取mybaits的配置文件
     String resource = "mybatis-config.xml";
     InputStream in =Resources.getResourceAsStream(resource);
     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //获得SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获得对应的类
        StudentMapper mapper = sqlSession.getMapper(UserMapper.class);
        //执行的方法
        List<User> users = mapper.selectUser();
        
        users.forEach(System.out::println);
        
    }

二、mybatis执行流程

在这里插入图片描述

执行流程:idea要打断点通过debug方式启动才看得到

1.Resources加载mybaits.xml的配置文件------>

2.实例化SqlSessionFactoryBuilder().build()------>

3.XMLConfigBuilder 解析mybatis.xml里面的配置 ------>

4.把配置信息存放到Configuration中------>

5.实例化SqlSessionFactory------>

6.由TransactionFactory创建一个Transaction事务对象------>

7.创建执行器Excutor------>

8.创建SqlSession接口------>

9.实现CRUD,如果执行成功就提交事务,失败就回滚到Transaction------>关闭

三、mybatis在插入语句中使用返回的主键-

 <insert id="addOrder" parameterType="OrderList" useGeneratedKeys="true" keyProperty="order_id" keyColumn="id">
     
//在service中这样获取   
public void addOrder(OrderList orderList) {
        int i = trainTicketOrderDao.addOrder(orderList);
        System.out.println("返回的条数i:"+i);
        System.out.println("返回的主键:"+orderList.getOrder_id());
    }     

四、mybatis中使用log4j日志

1.导入log4j的依赖

<!--日志-->
        <dependency>
            <groupId>slog4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

2.在resources目录中创建log4j.properties,并添加内容

##通过配置只查看com.kuang的namespace下的sql语句的日子
log4j.logger.com.kuang.dao=debug,console

#控制台附加器
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern= [%-5p][%d{yyyy-MM-dd HH:mm:ss}]%m%n

3.在mybatis-config.xml中添加属性,要注意按顺序

<!--要注意按顺序--> 
<settings >
        <setting name="logImpl" value="LOG4J" />
    </settings>

五、MyBatis缓存

  • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存

  • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)

  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存

1.一级缓存
  • 一级缓存只存在一个SqlSession里面,并且只有查询的时候才生效,session.close()的时候失效

  • 一级缓存失效的四种情况

    • 一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它
    • 增删改都会是刷新缓存
2.二级缓存
  • 开启二级缓存的步骤
    1. 开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
	2.在需要开启二级缓存的xxxMapper.xml中添加
<cache/>

<!--也可以这样配置-->
<cache
 eviction="FIFO"
 flushInterval="60000"
 size="512"
 readOnly="true"/>
<!--这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的
512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者
产生冲突。-->

注意:如果要使用二级缓存,实体类要序列号,不然会报错

3.缓存的执行顺序

用户-------->二级缓存-------->一级缓存-------->数据库

六、使用万能Map

在字段比较多的时候用map非常方便

  • 接口中

    //万能的map
    int addUser(Map<String, Object> map);
    
  • xml中

<!--用map类型,对象的属性可以直接取出来,传递map的key,
values后面可自定义名字,无需完全匹配数据库,对应参数中map的key
-->
<insert id="addUser" parameterType="map">
    insert into mybatis.user (id,name,password) values (#{id},#{username},#{password});
 </insert>
  • 测试
//添加
@Test
public void addUser1() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    Map<String, Object> map = new HashMap<String, Object>();
    map.put("id", 1);
    map.put("username", "马云");
    map.put("password", "666666");
    mapper.addUser(map);
    sqlSession.commit();//提交事务
	sqlSession.close();//关闭连接
}

七、使用foreach一次性插入批量数据

可以使用list,也可以使用map:

方式一:使用list

方式二:使用map

  • 接口中
//方式一:list
//批量添加
int insertUser_piliang(List<Map<String,Object>> list);

//方式二:map
//批量添加
int insertUser_piliang2(Map map);
  • mapper.xml中
 <!-- 方式一:list -->
     <insert id="insertUser_piliang" parameterType="java.util.List">
        insert into user(name,pwd) values
        <foreach collection="list" index="index" item="item" separator=",">
            (#{item.name},#{item.pwd})
        </foreach>
    </insert>

 <!-- 方式二:map -->
	<insert id="insertUser_piliang2" parameterType="map">
         insert into user(name,pwd) values
     <!--
        collection:指定输入对象中的集合属性
        item:每次遍历生成的对象
        open:开始遍历时的拼接字符串
        close:结束时拼接的字符串
        separator:遍历对象之间需要拼接的字符串
   -->
         <foreach collection="list" index="index" item="item" separator=",">
             (#{item.name},#{item.pwd})
         </foreach>
        
    </insert>
  • 测试
//方式一:list
@Test
    public void insertUser_piliang(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        HashMap<String, Object> map = new HashMap<>();
        for (int i = 0; i < 10; i++) {
            map.put("name", "邓紫棋");
            map.put("pwd", "666666");
            list.add(map);
        }
        mapper.insertUser_piliang(list);
        sqlSession.commit();
        sqlSession.close();
    }


//方式二:map
@Test
    public void insertUser_piliang2(){

        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String,Object> map = new HashMap<>();
        List<User> list = new ArrayList<>();
        User user = new User();
        
        //用for循环遍历添加100个User
        for (int i = 0; i < 100; i++) {
            user.setName("马云");
            user.setPwd("888888");
            list.add(user);
        }
        map.put("list", list);
        mapper.insertUser_piliang2(map);
        sqlSession.commit();//手动提交事务
        sqlSession.close();

    }

八、动态Sql

if语句

需求:根据用户名和密码查询,如果用户名为空,就根据密码查询,反之,密码为空,则根据用户名查询

  • 接口
List<User> queryUserIf(Map map);
  • xml
 <select id="queryUserIf" parameterType="map" resultType="User">
        select * from user
        <where>
            <if test="name != null">
            name=#{name}
            </if>
            <if test="pwd != null">
                and pwd=#{pwd}
            </if>
        </where>
</select>

这个 标签会知道如果它包含的标签中有返回值的话,它就插入一个 。此外,如果标签返
回的内容是以AND 或OR 开头的,则它会剔除掉。就是当name 的值为空时,会剔除掉and,有些案例直接用1=1

替换掉 ,但这是不安全的,存在sql注入问题。

  • 测试
//if查询
    @Test
    public void queryUser(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "李四");
        map.put("pwd", "888888");
        List<User> users = mapper.queryUserIf(map);
       users.forEach(System.out::println);
    }
set语句同 if 一样的原理,不举列了
choose 语句

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose
标签可以解决此类问题,类似于 Java 的 switch 语句

  • 接口
 //choose
    List<User> queryUserChoose(Map map);
  • xml
<select id="queryUserChoose" resultType="User" parameterType="map">
        select * from user
        <where>
            <choose>
                <when test="name != null">
                    name=#{name}
                </when>
                <when test="pwd != null">
                    and pwd=#{pwd}
                </when>
                <otherwise>
                    and id=#{id}
                </otherwise>
            </choose>
        </where>
    </select>
  • 测试
    • 测试结果:如果map中都没有值时,以id为主,如果name中有值,就以name为主查询,不关pwd的事
 //choose查询
    @Test
    public void queryUserChoose(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("pwd", "888888");

        map.put("id",2); //这是固定的,一定要有这个值
        List<User> users = mapper.queryUserChoose(map);
        users.forEach(System.out::println);
       
    }
模糊查询 like

转载csdn:https://blog.csdn.net/Crystalqy/article/details/79419244

常用的模糊查询有三种方法:**

  1. 直接使用 % 拼接字符串,如 '%'#{name}'%'"%"#{name}"%",单引号或双引号都可以。
  2. 使用concat(str1,str2)函数拼接
  3. 使用mybatis的bind标签
<!-- ******************** 模糊查询的常用的3种方式:********************* -->
    <select id="getUsersByFuzzyQuery" parameterType="User" resultType="User">
        select * from users
        <where>
            <!--
                方法一: 直接使用 % 拼接字符串 
                注意:此处不能写成  "%#{name}%" ,#{name}就成了字符串的一部分,
                会发生这样一个异常: The error occurred while setting parameters,
                应该写成: "%"#{name}"%",即#{name}是一个整体,前后加上%
            -->
            <if test="name != null">
                name like "%"#{name}"%"
            </if>
            <!--方法二: 使用concat(str1,str2)函数将两个参数连接 -->
            <if test="phone != null">
                and phone like concat(concat('%',#{phone}),'%')
            </if>
            <!--方法三: 使用 bind 标签,对字符串进行绑定,然后对绑定后的字符串使用 like 关键字进行模糊查询 -->
            <if test="email != null">
                <bind name="pattern" value="'%'+email+'%'"/>
                and email like #{pattern}
            </if>
        </where>
    </select>

九、多对一(以多方为主)

需求:查询学生的名字以及对应的老师的名字

多对一的理解:

  • 多个学生对应一个老师
数据库设计

在这里插入图片描述

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '潘老师');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=INNODB DEFAULT CHARSET=utf8
    
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', 1);
实体类
@Data //GET,SET,ToString,有参,无参构造
public class Teacher {
  private int id;
  private String name;
}
@Data
public class Student {
  private int id;
  private String name;
  //多个学生可以是同一个老师,即多对一
  private Teacher teacher;
}
按结果嵌套处理(这种方式比较简单)
1.接口方法编写
public List<Student> getStudents2(); 
2.编写对应的mapper文件
<!--
按查询结果嵌套处理
思路:
  1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher2" >
 select s.id sid, s.name sname , t.name tname
 from student s,teacher t
 where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
  <id property="id" column="sid"/>
    <result property="name" column="sname"/>
  <!--关联对象property 关联对象在Student实体类中的属性-->
  <association property="teacher" javaType="Teacher">
    <result property="name" column="tname"/>
  </association>
</resultMap>
测试
@Test
public void testGetStudents2(){
  SqlSession session = MybatisUtils.getSession();
  StudentMapper mapper = session.getMapper(StudentMapper.class);
  List<Student> students = mapper.getStudents2();
  for (Student student : students){
    System.out.println(
        "学生名:"+ student.getName()
            +"\t老师:"+student.getTeacher().getName());
 }
}

十、一对多(以一方为主)

需求:获取指定老师,及老师下的所有学生

一对多的理解:

  • 一个老师拥有多个学生
按结果嵌套处理(推荐方式)
TeacherMapper接口编写方法
//获取指定老师,及老师下的所有学生
public Teacher getTeacher(int id);
编写接口对应的Mapper配置文件
<mapper namespace="com.tong.mapper.TeacherMapper">
  <!--
  思路:
    1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
    2. 对查询出来的操作做结果集映射
      1. 集合的话,使用collection!
        JavaType和ofType都是用来指定对象类型的
        JavaType是用来指定pojo中属性的类型
        ofType指定的是映射到list集合属性中pojo的类型。
  -->
  <select id="getTeacher" resultMap="TeacherStudent">
   select s.id sid, s.name sname , t.name tname, t.id tid
   from student s,teacher t
   where s.tid = t.id and t.id=#{id}
  </select>
  <resultMap id="TeacherStudent" type="Teacher">
    <result  property="name" column="tname"/>
    <collection property="students" ofType="Student">
      <result property="id" column="sid" />
      <result property="name" column="sname" />
      <result property="tid" column="tid" />
    </collection>
  </resultMap>
</mapper>
测试
@Test
public void testGetTeacher(){
  SqlSession session = MybatisUtils.getSession();
  TeacherMapper mapper = session.getMapper(TeacherMapper.class);
  Teacher teacher = mapper.getTeacher(1);
  System.out.println(teacher.getName());
  System.out.println(teacher.getStudents());
}

总结:

  • 使用mybatis时,增删改查都需要提交事务,否则运行成功并没有添加到数据库

  • 可以手动提交事务,也可以在openSession()是设置为true,此时不用每次都手动提交了

    • 这是在自定义的MybatisUtil工具包中

      //获取SqlSession连接
          public static SqlSession getSqlSession() {
              return sqlSessionFactory.openSession(true);//设置为true
          }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值