Mybatis框架以及动态sql

1. mybatis框架

框架:别人搭建好的某些功能,只需要引用该框架并加入自己的业务代码。

好处: 提高开发效率。

mybatis的介绍:

MyBatis 是一款优秀的持久层Dao框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Java实体类)映射成数据库中的记录.

2. 为什么使用mybatis框架

可以简化jdbc的操作以及占位符赋值以及查询结果集的封装。

3. 如何使用mybatis.

(1)引入mybatis和mysql的jar包

        <!--mybatis驱动-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
​
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

(2) 创建mybatis的配置文件,命名为:mybatis.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>
​
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
    <!--注册映射文件-->
    <mappers>
        <mapper resource="mapper/userMapper.xml"/>
    </mappers>
</configuration>

(3) 创建实体类(用Lombok插件)

@Data(自动生成get和set方法)
@NoArgsConstructor(无参构造)
@AllArgsConstructor(有参构造)
public class User {
    private Integer id;
    private String name;
    private int email;
​
    public User(String name, int email) {
        this.name = name;
        this.email = email;
    }
}

(4) 创建mybatis和数据库的映射文件.命名为:xxx.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">
​
<!--namespace:命名空间,可以随便起名,后期要求命名空间的值必须和所对应的dao相同-->
<mapper namespace="com.cmw.entity.Student">
    <!--查询 根据id查询用户信息
        select标签用于查询的标签
            id:标签的唯一标识
            resultType:定义返回的类型,把sql查询的结果封装到那个实体类中
            parameterType:参数类型
            #{id}===》表示占位符 等价? 是mybatis的框架语法
            #{必须和属性对应}
    -->
    <select id="findById" resultType="Student">
        select * from student where id=#{id}
    </select>

(4) 测试mybatis

package com.cmw.test;
​
import com.cmw.entity.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
​
import java.io.Reader;
​
/**
 * @Author 86151
 * @Create 2022/5/31 - 15:18
 */
public class Test01 {
    public static void main(String[] args) throws Exception{
        //1.读取mybatis配置文件的内容
        Reader reader= Resources.getResourceAsReader("mybatis.xml");
        //2.获取SqlSessionFactory对象
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        //3.获取SqlSession对象----封装了对数据库操作的各种方法
        SqlSession session= factory.openSession();
​
        //调用查询一个结果的接口 String statement:命名空间+id---指向SQL标签
        //                   Object parameter:需要实参
        Student student =session.selectOne("com.cmw.entity.Student.findById","2");
        System.out.println(student);
        //4.关闭
        session.close();
    }
}

4. 使用mybatis完成crud(即增删改查)

<?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">
​
<!--namespace:命名空间的值必须和所对应的dao相同-->
<mapper namespace="com.cmw.entity.Student">
    <!--查询 根据id查询用户信息
        select标签用于查询的标签
            id:标签的唯一标识
            resultType:定义返回的类型,把sql查询的结果封装到那个实体类中
            parameterType:参数类型
            #{id}===》表示占位符 等价? 是mybatis的框架语法
            #{必须和属性对应}
    -->
    <select id="findById" resultType="Student">
        select * from student where id=#{id}
    </select>
​
    <!--增加-->
    <insert id="add" parameterType="Student">
        insert into student values(null ,#{name},#{realname})
    </insert>
    <!--删除-->
    <delete id="delete" parameterType="int">
        delete from student where id=#{id}
    </delete>
    <!--修改-->
    <update id="update" parameterType="Student">
        update student set name=#{name},realname=#{realname} where id=#{id}
    </update>
    <!--查询所有-->
    <select id="findAll" resultType="Student">
        select * from student
    </select>
</mapper>

测试:

package com.cmw.test;
​
import com.cmw.entity.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
​
import java.io.Reader;
import java.util.List;
​
/**
 * @Author 86151
 * @Create 2022/5/31 - 16:13
 */
public class Test1 {
//添加
    @Test
    public void testAdd() throws Exception{
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session = factory.openSession();
        Student student=new Student();
        student.setName("lm");
        student.setRealname("黎明");
        int row = session.insert("com.Student.add", student);
        System.out.println(row);
​
        session.commit();
        session.close();
    }
//删除
    @Test
    public void testDelete() throws Exception{
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session = factory.openSession();
​
        int delete = session.delete("com.Student.delete", 1);
        System.out.println(delete);
        session.close();
    }
//修改
    @Test
    public void testUpdate() throws Exception{
        //1.读取mybatis配置文件的内容
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        //2.获取SqlSessionFactory对象
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        //3.获取SqlSession对象---封装了对数据库的各种方法
        SqlSession session = factory.openSession();
        Student student=new Student(3,"xx","嘻嘻");
        int i = session.update("com.Student.update", student);
        System.out.println(i);
        //提交查询
        session.commit();
        session.close();
    }
//查询所有
    @Test
    public void testFindAll() throws Exception{
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session = factory.openSession();
        List<Object> list = session.selectList("com.Student.findAll");
        System.out.println(list);
        session.commit();
        session.close();
    }
}

5. mybatis一些优化

5.1 为实体类起别名

mybatis.xml配置文件

<typeAliases>
        <!--单独为某个实体类 起个别名
        <typeAlias type="com.cmw.entity.Student" alias="student"/>-->
        <!--为指定包下的实体类 起个别名 该别名就是实体类名-->
        <package name="com.cmw.entity"/>
    </typeAliases>

5.2 添加sql日志

(1)添加日志的jar.(在pom.xml里面添加)

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

(2) 添加日志的文件配置且命名为:log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
​
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
​
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D:/qy151/log/qy151.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
​
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

6. 通过dao和映射文件的关联来完成操作---企业开发模式

由于SqlSession封装的方法,传递的参数statement, 传递占位符的参数只能传递一个。而且他的方法名称都是固定。而真实在开发环境下我们不使用SqlSession封装的方法,习惯自己定义方法,自己调用自己的方法。

(1)创建一个dao接口并定义自己需要的方法。

package com.cmw.dao;
​
import com.cmw.entity.User;
import org.apache.ibatis.annotations.Param;
​
import java.util.List;
​
public interface UserDao {
    //查询所有用户的信息
    public List<User> findAll();
}

(2)创建映射文件

<?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.cmw.dao.UserDao">
    <!--查找所有-->
    <select id="findAll" resultType="com.cmw.entity.User">
        select * from tb_user
    </select>
</mapper>

注意: namespace必须和dao接口一样,标签的id必须和接口的方法名一样。

(3)测试

package com.cmw.test;
​
import com.cmw.dao.UserDao;
import com.cmw.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
​
import java.io.Reader;
import java.util.List;
​
/**
 * @Author 86151
 * @Create 2022/6/1 - 10:47
 */
public class TestUserDao {
    //查询所有
    @Test
    public void testFindAll() throws Exception{
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session = factory.openSession();
        UserDao userDao = session.getMapper(UserDao.class);//获取接口的映射类
​
        List<User> list = userDao.findAll();
        System.out.println(list);
        session.commit();
        session.close();
    }

7.传递多个参数。

我们在dao接口中某些方法可能需要传递多个参数,需要在参数处使用@Param()为参数起名。

package com.cmw.dao;
​
import com.cmw.entity.User;
import org.apache.ibatis.annotations.Param;
​
import java.util.List;
​
public interface UserDao {
    /**
     * 根据id查询用户信息
     * @param name
     * @param email
     * @return
     */
    //@param 表示把该参数的名称作为映射文件的参数名
    public User findNameAndEmail(@Param("name")String name,@Param("email")int email);
}

8.添加时如何返回递增的主键值。

需要返回添加数据库后的id值。

<!--添加内容
        useGeneratedKeys:设置使用生成的主键
        keyProperty:赋值给哪个属性
    -->
    <insert id="add" parameterType="com.cmw.entity.User" useGeneratedKeys="true" keyProperty="id">
        insert into tb_user values(null,#{name},#{email})
    </insert>

测试及结果

//添加
    @Test
    public void testAdd() throws Exception{
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session = factory.openSession();
        UserDao userDao = session.getMapper(UserDao.class);
​
        User user=new User("赵六",7415);
        System.out.println("添加前的id"+user);
        userDao.add(user);//添加user
        System.out.println("添加后的id"+user);
        session.commit();
        session.close();
    }

9.解决列名和属性名不一致。

问题: 查询时返回一个null,或者某个列没有值

可以有两种解决办法:

第一种: 为查询的列起别名,而别名和属性名一致。

 <!--根据id查询学生信息-->
   <select id="findOne" resultType="com.cmw.entity.Student">
        select tb_id id,tb_name name,tb_age age,sex from tb_stu where tb_id=#{id}
    </select>

第二种: 使用resultMap完成列和属性之间的映射关系。

<!--resultType和resultMap 二者只能用一个-->
    <resultMap id="stuMapper" type="com.cmw.entity.Student">
        <!--主键的映射关系 column:列名  property:属性名-->
        <id column="tb_id" property="id"/>
        <!--普通列的映射关系-->
        <result column="tb_name" property="name"/>
        <result column="tb_age" property="age"/>
    </resultMap>
    <select id="findOne" resultMap="stuMapper">
        select * from tb_stu where tb_id=#{id}
    </select>

注意:resultMap的id 和 select的resultMap的值一样

如果列名和属性名有个别一致的,可以在resultMap中不写映射关系

10. 动态sql

10.1 什么是动态sql:

顾名思义,SQL 是动态拼接成的,根据传入的变量值进行逻辑操作,并动态拼接,方便实现多条件下的数据库操作。 在业务逻辑复杂,即简单 SQL 无法完成时,需要拼接时就要使用动态 SQL。

10.2 mybatis中动态sql标签有哪些?

if:
适用于动态的包含where字句的一部分
if的特点是
当if的判断条件满足时,添加if标签中的字句
当if的判断条件不满足时,什么都不添加
choose:
适用于:
当判断的条件为true时,执行一个语句
当判断的条件为false时,执行另一个语句
where和set:
where的作用:
1、当where标签中的语句不为空时,会在语句之前拼接上“where”关键字
2、假如where标签中的语句是以“and”或者“or”开头,那么这个“and”或者“or”会被省略掉
set的作用:
1、假如set标签中的语句不为空,那么会在开头拼接“set”关键字
2、假如set标签中的语句是以“,”结尾,那么这个“,”会被去掉
Trim:
prefix:前缀,在赶回的字符串之前添加什么内容
suffix:后缀,在返回的字符串之后添加什么内容
prefixoverrides:当字符串以其中的内容开头时,该内容会被覆盖
suffixoverrides:当字符串以其中的内容结尾时,该内容会被覆盖
Foreach:
注意:当接口中方法的参数为数组或者集合时,mybatis会自动的把该参数封装成一个map
map的key为参数类型,首字母小写
默认:数组的key为“array”,集合的key为“list”,map的key为“map”
collection:参数在封装成的map中的key值
open:表示字符串以什么开始
close:表示字符串以什么结束
item:给集合中的每一个元素起的别名
separator:集合中元素的分隔符

10.3 if标签--单条件判断

package com.cmw.dao;
​
import com.cmw.entity.Account;
import org.apache.ibatis.annotations.Param;
​
import java.util.List;
​
public interface AccountDao {
    //如果name不为null,则按照name查询,如果为null则查询所有
    public List<Account> findByCondition(@Param("name")String name,@Param("money")Double money);
}
 
<select id="findByCondition" resultType="com.cmw.entity.Account">
        select * from account where 1=1
            <if test="name!=null and name!=''">
                and name=#{name}
            </if>
            <if test="money!=null">
                and money=#{money}
            </if>
    </select>

10.4 choose和when标签 多条件分支判断

package com.cmw.dao;
​
import com.cmw.entity.Account;
import org.apache.ibatis.annotations.Param;
​
import java.util.List;
​
public interface AccountDao {
    //choose
    public List<Account> findByCondition2(@Param("name")String name,@Param("money")Double money);
}
<select id="findByCondition2" resultType="com.cmw.entity.Account">
        select * from account where 1=1
        <choose>
            <when test="name!=null and name!=''">
                and name=#{name}
            </when>
            <when test="money!=null">
                and money=#{money}
            </when>
            <otherwise>
                and isdeleted=0
            </otherwise>
        </choose>
    </select>

10.5 where标签

我们观察到上面的sql都加了 where 1=1 ,如果不使用where 1=1 那么你的动态sql可能会出错。 我们能不能不加where 1=1呢! 可以 那么我们就可以使用where标签,作用:可以自动为你添加where关键字,并且可以帮你去除第一个and |or

<select id="findByCondition" resultType="com.cmw.entity.Account">
        select * from account
        <where>
            <if test="name!=null and name!=''">
                and name=#{name}
            </if>
            <if test="money!=null">
                and money=#{money}
            </if>
        </where>
    </select>

10.6 set标签

配合if标签一起用,一般用在修改语句。如果传递的参数值为null,那么应不修改该列的值。

<!--set:生成关键字set 并且可以去除最后一个逗号-->
    <update id="update">
        update account
        <set>
            <if test="name!=null and name=''">
                name =#{name},
            </if>
            <if test="money!=null">
                money=#{money},
            </if>
            <if test="isdeleted!=null">
                isdeleted=#{isdeleted},
            </if>
            <if test="created!=null">
                created=#{created},
            </if>
            <if test="updated!=null">
                updated=#{updated},
            </if>
        </set>
            where id=#{id}
    </update>

10.7 foreach标签

循环标签.

查询:

   
<sql id="a">
        id,name,money,isdeleted,created,updated
    </sql>
    <select id="findByIds" resultType="com.cmw.entity.Account">
        select <include refid="a" /> from account where id in(
        <foreach collection="array" item="id" separator=",">
            #{id}
        </foreach>)
    </select>

删除:

<delete id="batchDelete">
        delete  from account where id in (
            <foreach collection="array" item="id" separator=",">
                #{id}
            </foreach>
            )
    </delete>

添加:

  <insert id="batchAdd">
        insert into account(name ,isdeleted) values
        <foreach collection="list" item="acc" separator=",">
            (#{acc.name},#{acc.isdeleted})
        </foreach>
    </insert>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值