学习笔记——Mybatis

引入

1.jdbc, Dbutils(工具类), jdbcTemplate(spring的)

sql语句编写在java代码里,硬编码高耦合

2.Hibernate:全自动ORM(Object Relation Mapping)框架旨在消除sql

编写sql,预编译,设置参数,执行sql,封装结果处于黑箱

黑箱操作,无法自定义编写sql,希望可以将sql交给开发人员

3.引出mybatis(半自动)

​ sql语句编写在配置文件

​ 预编译,设置参数,执行sql,封装结果处于黑箱

​ sql与java编码分离,sql是开发人员控制

配置

导入依赖

 <!--MyBatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

项目打包编译是打包项目包中的.class文件和resourses中的xml文件,所以一般在resourses中放xml文件

所以希望xml文件在项目包的话,要加以下依赖

<resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>

主配置文件

包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器

<?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核心配置文件-->
<configuration>
    <!--environments配置环境组-->
    <!--default默认环境-->
    <environments default="development">
        <!--environment单个环境-->
        <environment id="development">
            <!--transactionManager配置事务管理器-->
            <transactionManager type="JDBC"/>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://rm-bp1u4664aff1hip7plo.mysql.rds.aliyuncs.com:3306/practice?"/>
                <property name="username" value="root"/>
                <property name="password" value="Aa123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--每一个Mapper.xml需要在Mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="StudentDao.xml"/>
    </mappers>
</configuration>

工具类

将固定步骤放入此类,去除了冗余的操作

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。 SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

public class MyBatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //使用mybatis第一步、获取sqlSessionFactory对象
            String resource = "mybatis.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //既然有了 SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了。
    // SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }

}

例子

1.创建student表

CREATE TABLE `student`
( 
id INT NOT NULL, 
`name` VARCHAR NULL, 
email VARCHAR NULL, 
age INT NULL, 
PRIMARY KEY(id)
)
CHARACTER SET utf8 COLLATE utf8_bin ENGINE INNODB;

2.创建实体类

属性名和列名保持一致(也可以取别名)

package practice01.domain;

public class Student {
    private int id;
    private String name;
    private String email;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

3.创建Dao层,定义操作数据库方法

​ 创建个dao包,创建接口和方法

public interface StudentDao {

    Student selectStudentById(int id);
}

4.创建xml文件写sql语句

​ 在resources里创建个dao包,里面写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="practice01.dao.StudentDao">

    <!--
       id是自定义标识,推荐使用接口方法
       resultType告诉mybatis执行sql语句后将数据类型赋值的对象类型
    -->
    <select id="StudentDao" resultType="practice01.domain.Student">
       select * from student where id=#{id}
    </select>

</mapper>

id是自定义标识,推荐使用接口方法

resultType告诉mybatis执行sql语句后将数据类型赋值的对象类的全名(底层通过反射创建对象)

namespaces=接口的全类名(eclipse)[namespaces=接口名(idea)]
id =接口中的方法名
parameterType=方法中的参数类型
SQL语句中的参数=方法中的参数名

属性名和列名保持一致(也可以取别名)

5.在mybatis的主配置文件注册

 <mappers>
        <mapper resource="StudentDao.xml"/>
    </mappers>

6.测试

SqlSession 提供了在数据库执行 SQL 命令所需的所有方法

SqlSession sqlSession = MyBatisUtils.getSqlSession();
Student student = sqlsession.selectOne("selectStudentById",1);
 

selectOne

selectList

selectMap

insert delete update

另一种方法,此方法直接调用接口的方法和参数,比较明显好用

public class Mytest {

    @Autowired
    private StudentDao studentDao;
    @Test
    void test()
    {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
      //创建接口的代理对象
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        Student student = studentDao.selectStudentById(1);
        System.out.println(student);
        sqlSession.close()
        
    }
}

直接映射到在命名空间中同名的映射器类,并将已映射的 select 语句匹配到对应名称、参数和返回类型的方法。因此你就可以像上面那样,不费吹灰之力地在对应的映射器接口调用方法

黑色加粗字是底层的实现

底层原理

主配置文件:

数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器。读取XML配置文件后会将内容放在一个Configuration类中,Configuration类会存在整个Mybatis生命周期,以便重复读取。

SqlSessionFactory:

创建SqlSession实例,是单例的。因为每次访问数据库都需要一个SqlSession,所以SqlSessionFactiory的生命周期是贯穿整个Mybatis生命周期的,SqlSessionFactiory采用单例的原因是减少数据库连接资源

SqlSession:

SqlSession是一个会话,类似于jdbc的connection,它的生命周期是在请求数据库处理事务过程中,他是一个线程不安全的对象。多线程操作时因多注意他的隔离级别和数据库锁等。SqlSession使用需及时关闭

两种使用:

1.获取对应的Mapper,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果。

映射底层是动态代理,将执行接口方法通过反射抽象成method,在invoke函数先判断,如果是类的方法的话直接执行。如果不是类的话,将method传给MapperMethod对象。MapperMethod.execute()底层会调用sqlSwssion执行sql语句。这里动态代理相当于给了实现接口抽象方法的方法体

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
       return method.invoke(this, args);
    }
    MapperMethod mapperMethod = cachedMapperMethod(method);
     return mapperMethod.execute(this.sqlSession, args);
   }



private MapperMethod cachedMapperMethod(Method method) {
     MapperMethod mapperMethod =    (MapperMethod)this.methodCache.get(method);
   if (mapperMethod == null) {
     mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
       this.methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

2.直接使用SqlSession,通过命名信息去执行SQL返回结果,该方式是IBatis版本留下的,SqlSession通过Update、Select、Insert、Delete等方法操作

基于JDBC的改进,思路没变

resultMap和resultType

MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap.

resultType表示返回的数据类型,其实类属性和表字段底层已经映射过了。属性名和表的字段名一致,根据名字映射上。

resultMap适合比较复杂的查询,类属性和表字段名字不一致时,用resultMap提前映射好。

在这里插入图片描述

java类中定义的名字如图所示

在这里插入图片描述

可以看到他们不一样,需要有一个映射关系。这样避免过多的对代码进行修改。
需要在Mapper.xml中对数据进行映射,就可以用到resultmap

 -->
	<resultMap id="userMap" type="com.itheima.domain.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>

resultType就需要替换成resultMap

<select id="findAll" resultMap="userMap">
		select * from user

	</select>
		<insert id="saveUser" parameterType="com.itheima.domain.User">insert into USER (username,address,sex,birthday) values (#{username},#{address},#{sex},#{birthday});

</insert>
	<update id="updateUser" parameterType="com.itheima.domain.User">

		UPDATE user set username=#{username},address=#{address},sex=#{sex} where id=#{id}
	</update>
	<delete id="deleteUser" parameterType="java.lang.Integer">

		delete from user where id=#{id}
	</delete>

	<select id="findUserById" resultMap="userMap">
		select * from user where id=#{id}
	</select>

	<select id="findUserByName" resultMap="userMap">
		select * from user where username like #{username}
	</select>

#{}和${}

#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理s{}时,就是把s{}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。

CRUD

sql语句是mysql的内容

package com.newer.dao;
 
import com.newer.pojo.User;
 
import java.util.List;
 
public interface UserMapper {
 
    //查询全部用户
    List<User> getUserList();
 
    //根据ID查询用户
    User getUserById(int id);
 
    //insert一个用户
    int addUser(User user);
 
    //修改用户
    int updateUser(User user);
 
    //删除用户
    int deleteUser(int id);
}
<?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绑定一个对应的Mapper接口-->
<mapper namespace="com.newer.dao.UserMapper">
   <select id="getUserList" resultType="com.newer.pojo.User">
       select * from mybatis.user
   </select>
 
    <select id="getUserById" parameterType="int" resultType="com.newer.pojo.User">
        select * from mybatis.user where id=#{id}
    </select>
 
    <insert id="addUser" parameterType="com.newer.pojo.User">
        insert into mybatis.user (id,name,pwd) values (#{id},#{name },#{pwd})
    </insert>
 
    <update id="updateUser" parameterType="com.newer.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
    </update>
 
    <delete id="deleteUser" parameterType="int">
        delete  from mybatis.user where id=#{id}
    </delete>
</mapper>
多对一查询
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.newer.dao.StudentMapper">
 
    <!--按照结果嵌套处理-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from student s,teacher t
        where s.tid=t.id
    </select>
    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"></result>
        <result property="name" column="sname"></result>
        <association property="teacher" javaType="Teacher">
            <result property="id" column="tid"></result>
            <result property="name" column="tname"></result>
        </association>
    </resultMap>
</mapper>
一对多查询
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.newer.dao.TeacherMapper">
    <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=#{tid}
    </select>
 
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"></result>
        <result property="name" column="tname"></result>
        <collection property="students" ofType="Student">
            <result property="id" column="sid"></result>
            <result property="name" column="sname"></result>
            <result property="tid" column="tid"></result>
         </collection>
    </resultMap>
 
 

mysql多对一查询

  • 子查询

  • 联表查询

    一对多和多对一都是多表查询,如一个老师对应多学生,多学生对应一个老师。只是返回的对象不同。

    模糊查询
    string wildcardname =%smi%; 
    list<name> names = mapper.selectlike(wildcardname);
    
    <select id=”selectlike”> 
     select * from foo where bar like #{value} 
    </select>
    
分页查询
limit
select * from user limit startIndex,pageSize
//分页
List<User> getUserByLimit(Map<String,Integer> map);
@Test
    public void getUserByLimit(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Integer> map = new HashMap<>();
        map.put("startIndex",0);
        map.put("pageSize",2);
 
   List<User> userList = mapper.getUserByLimit(map);
   for (User user : userList) {
       System.out.println(user);
   }
   sqlSession.close();
}
RowBounds分页

不通过sql语句实现分页

List<User> getUserByRowBounds();
<!--分页2-->
 <select id="getUserByRowBounds" resultMap="UserMap">
     select * from mybatis.user
 </select>
@Test
 public void getUserByRowBounds(){
     SqlSession sqlSession = MyBatisUtils.getSqlSession();
     //RowBounds实现
     RowBounds rowBounds = new RowBounds(1, 2);
 
     //通过java代码层面实现分页
     List<User> userList = sqlSession.selectList("com.rui.dao.UserMapper.getUserByRowBounds",null,rowBounds);
 
     for (User user : userList) {
         System.out.println(user);
     }
     sqlSession.close();
 }
parameterType

@Param是告诉sql参数名称,而parameterType是告诉sql参数类型。

方法参数的类型是基本数据类型的话没必要写。sql语句#{}中填写参数名即可。

方法参数的类型是类的话,parameterType后填写对应的类,#{}中填写

方法参数的类型是类也可以给类取别名,然后#{}中类别名.成员变量名

我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map

Map
int addUser2(Map<String,Object> map);
<!--对象中的属性,可以直接取出来 parameterType=传递map中的key-->
<insert id="addUser2" parameterType="map">
    insert into mybatis.user (id, name, pwd) values (#{userId},#{userName},#{password});
</insert>
@Test
public void addUser2(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put(“userId”,4);
map.put(“userName”,“王五”);
map.put(“password”,23333);
mapper.addUser2(map);
//提交事务
sqlSession.commit();
sqlSession.close();
}

map中的key作为sql语句的参数

动态Sql

传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误。Mybatis的动态SQL功能正是为了解决这种问题, 其通过 if, choose, when, otherwise, trim, where, set, foreach标签,可组合成非常灵活的SQL语句,从而提高开发人员的效率。下面就去感受Mybatis动态SQL的魅力吧。

if
<select id="findUserById" resultType="user">
    select * from user where 
        <if test="id != null">
               id=#{id}
        </if>
    and deleteFlag=0;
</select>

上面例子: 如果传入的id 不为空, 那么才会SQL才拼接id = #{id}。 这个相信大家看一样就能明白,不多说。细心的人会发现一个问题:“你这不对啊! 要是你传入的id为null, 那么你这最终的SQL语句不就成了 select * from user where and deleteFlag=0, 这语句有问题!”

where
<select id="findUserById" resultType="user">
    select * from user 
        <where>
            <if test="id != null">
                id=#{id}
            </if>
            and deleteFlag=0;
        </where>
</select>
set
<update id="updateUser" parameterType="com.dy.entity.User">
    update user
        <set>
            <if test="name != null">name = #{name},</if> 
            <if test="password != null">password = #{password},</if> 
            <if test="age != null">age = #{age}</if> 
        </set>
        <where>
            <if test="id != null">
                id = #{id}
            </if>
            and deleteFlag = 0;
        </where>
</update>
choose

Java中有switch, mybatis有choose

<select id="findActiveBlogLike"
     resultType="Blog">
    SELECT * FROM BLOG WHERE state = ‘ACTIVE’
    <choose>
        <when test="title != null">
            AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
            AND author_name like #{author.name}
        </when>
        <otherwise>
            AND featured = 1
        </otherwise>
    </choose>
</select>

当title和author都不为null的时候, 那么选择二选一(前者优先), 如果都为null, 那么就选择 otherwise中的, 如果tilte和author只有一个不为null, 那么就选择不为null的那个

注解

@Param

@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中

 public int getUsersDetail(@Param("userid") int userid);
 <select id="getUserDetail" statementType="CALLABLE" resultMap="baseMap">
          Exec WebApi_Get_CustomerList #{userid}
 </select>
void mysave(@Param("pac123") Pac pac);
<insert id="mysave" parameterType="com.example.xmlsax_reader.entity.Pac">
        insert into pac(productlevel,satelliteid) values (#{pac123.productLevel},#{pac123.satelliteID})//#{参数名.成员变量名}
</insert>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值