实训总结day2(mybatis基本概念,框架搭建,动态代理方式,增删改查,模糊查询,解决字段命名冲突)

什么是Mybatis:

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatisc框架执行sql并将结果映射成java对象并返回。

什么是ORM?什么是持久化?

ORM(Object Relational Mapping):对象关系映射
编写程序的时候,以面向对象的方式处理数据,保存数据的时候,却以关系型数据库的方式存储。

将程序中数据在瞬时状态和持久状态间转换的机制.:
在这里插入图片描述
代码中:
在这里插入图片描述
持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装

Mybatis基本概念

  1. SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
    mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
  2. 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
  3. 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
  4. mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  5. Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
  6. Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
  7. Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

Mybatis框架搭建:

SqlMapConfig.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="db.properties"></properties>
    <!--设置日志打印输出(标准日志输出)-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--定义别名-->
    <typeAliases>
        <typeAlias type = "com.oracle.xiaomi.pojo.Users" alias = "users"></typeAlias>
    </typeAliases>
    <!--数据库环境配置-->
    <environments default="development">
        <environment id="development">
            <!--事务处理的方式-->
            <!--追mybatis源码,事务处理的方式除了JDBC还有managed(容器来管理)-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource的取值还有(POOLED:说明用数据库连接池执行mybatis框架的配置)-->
            <!--(JNDI:表示用java命名接口来进行配置,这种方式不使用数据库连接池)-->
            <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>
    <!--注册mapper文件-->
    <mappers>
        <!--<mapper class = "com.oracle.xiaomi.mapper.UsersMapper"></mapper>-->
        <!--利用打包的方式注册mapper文件-->
        <package name="com.oracle.xiaomi.mapper"/>
    </mappers>
</configuration>

db.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

log4j.properties:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=zar.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l  %m%n

log4j.rootLogger=debug,file,stdout

利用动态代理方式书写映射文件:

三大配置文件写好之后,接下来我们来写mapper
Mapper英文翻译过来意思是:“映射;字体映射程序”
我们要使用动态代理的方式来写mapper,也就是说,要写一个mapper的接口,这个接口里面定义了我们所有的增删改查操作,然后写一个mapper的xml文件,该文件用标签来封装具体实现某一操作的SQL语句。
注意:要使用接口来实现动态代理,我们要保证mapper的接口名和mapper的xml文件名必须一致,并且放置在同一个包下!
先定义mapper的接口类,以UsersMapper.java文件为例:

package com.oracle.xiaomi.mapper;
import com.oracle.xiaomi.pojo.Users;
import java.util.List;
//mapper的接口名和mapper的xml文件名必须一致,并且放置在同一个包下!
    //通过接口的方式来动态代理
public interface UsersMapper {
    public int save(Users u);
    public int delete(Integer id);
    public int update(Users u);
    public Users getById(Integer id);
    public List<Users> getAll();
    //根据用户名来查用户的信息,而且是模糊查询
    public List<Users> getByUserName(String userName);
}

然后写与之对应的具体实现文件mapper.xml。以UsersMapper.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-->
<mapper namespace="com.oracle.xiaomi.mapper.UsersMapper">
    <!--sql标签可以将重复的SQL语句封装起来,下次使用时通过include标签的refid属性引用其id号即可-->
    <sql id="allCloums">
        id,userName,birthday,sex,address
    </sql>
    <!--sql语句不要写分号;#{}有一个要求,如果你的入参是8种数据类型+String,那么大括号里可以随便写,写啥都行,
    但是如果入参是一个引用类型,那么这个大括号里填的必须是这个对象的成员变量;
    mapper文件写完之后必须立马在SqlMapConfig.xml文件中进行注册-->
    <select id="getById" parameterType="int" resultType="users">
        select <include refid="allCloums"></include> from users where id = #{id}
    </select>
    <select id="getAll" resultType="users">
        select <include refid="allCloums"></include> from users
    </select>
    <insert id="save" parameterType="users">
        insert into users(username, birthday, sex, address) values (#{userName},#{birthday},#{sex},#{address})
    </insert>
    <!--删除用户-->
    <delete id="delete" parameterType="users">
        delete from users where id = #{id};
    </delete>
    <!--更新用户-->
    <update id="update" parameterType="users">
        update users set username = #{userName},sex = #{sex},birthday = #{birthday},address = #{address} where id = #{id}
    </update>
    <!--根据用户名来查用户信息-->
    <!--模糊查询:放在字符串中间用来拼接都要用${}-->
    <select id="getByUserName" parameterType="string" resultType="users">
        select <include refid="allCloums"></include>
        from users where username like '%${value}%'
    </select>
    <!--%%获取参数 '% ${value} %'
       如果是基本数据类型,${}里用value来占位,如果是对象,${}的值是对象的字段名-->
</mapper>

几个注意的点:

  1. 我们可以按住Ctrl键跟踪到xml文件头声明的这么一个.dtd文件中,查看该文件中可以定义的标签有哪些,这些标签可以有哪些属性以及这些标签的定义顺序。
  2. mapper标签里一定要写namespace
  3. sql标签可以将重复的SQL语句封装起来,下次使用时通过include标签的refid属性引用其id号即可
  4. sql语句结尾处不要写分号
  5. #{}有一个要求,如果你的入参是8种数据类型+String,那么大括号里可以随便写,写啥都行,
    但是如果入参是一个引用类型,那么这个大括号里填的必须是这个对象的成员变量
  6. ${}的要求:如果大括号里是基本数据类型,${}里用value来占位,如果是对象,${}的值是对象的字段名
  7. select,update,delete,insert标签内部写sql语句的地方只能写sql语句,不要写任何注释或其他任何代码,以免产生不必要的麻烦
  8. mapper文件写完之后必须立马在SqlMapConfig.xml文件中进行注册,以免忘记注册

测试增删改查:

写好之后,创建一个test包,在Test类之下进行Junit测试:

package com.oracle.xiaomi.test;

import com.oracle.xiaomi.mapper.UsersMapper;
import com.oracle.xiaomi.pojo.Users;
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.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MyTest {
    //创建连接对象
    SqlSession sqlSession;
    //创建UsersMapper对象
    UsersMapper usersMapper;
    //@Before注解:在Junit测试中,所有的测试方法在测试之前都要先自动去调用@Before注解的方法
    @Before
    public void setSession() throws Exception{
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = factory.openSession();
        usersMapper = sqlSession.getMapper(UsersMapper.class);//反射机制
    }
    @Test
    public void testGetById(){
        //usersMapper = sqlSession.getMapper(UsersMapper.class);//反射机制
        //现在这个userMapper对象就可以理解为UsersMapper.xml文件中的select标签的全部内容
        Users u = usersMapper.getById(1);
        //输出语句的快捷键:sout+回车
        System.out.println(u);
    }
    @Test
    public void testGetAll(){
       // usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.getAll();
        System.out.println(list);
    }
    @Test
    public void TestSave(){
        Users u = new Users();
        u.setBirthday(new Date());
        u.setSex("男");
        u.setUserName("王二");
        u.setAddress("上海");
        int num = usersMapper.save(u);
        System.out.println(num);
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void testDelete(){
        int num = usersMapper.delete(1);
        sqlSession.commit();
        sqlSession.close();
    }
    //更新操作必带主键
    @Test
    public void testUpdate(){
        Users u = new Users();
        u.setBirthday(new Date());
        u.setSex("男");
        u.setUserName("飞哥");
        u.setAddress("123宿舍");
        u.setId(1);
        int num = usersMapper.update(u);
        System.out.println(num);
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void testgetByUserName(){
        List<Users> list = usersMapper.getByUserName("张三");
        for(Users u : list){
            System.out.println(u);
        }
    }
}

注意以下几个点:

  1. 这里每个测试方法的返回值都是void
  2. 这里每个测试方法都不带参数,具体需要的参数在方法体里面写
  3. Junit测试中@Before注解的含义:在Junit测试中,所有的测试方法在测试之前都要先自动去调用@Before注解的方法
  4. 因为在@Before注解过的方法里我们使用了SqlSessionFactory的openSession()方法来生成一个sqlSession,因此我们每一步使用sqlSession对象之后都要去关闭连接:sqlSession.close();
  5. 除查询操作以外,增加,删除,修改操作都要使用sqlSession.commit();进行真正意义上的修改数据库。
  6. 插入操作我们为了使id实现自增,插入时不必提供主键
  7. 更新操作必带主键,因为要明确更新的是哪一行记录。

模糊查询的几种写法(针对MySQL数据库):

1. MyBatis ${ }拼接符

它可以完成字符串原样拼接,如果传入的参数是基本类型(string,long,double,int,boolean,float等),那么${}中的变量名称必须是value
注意:拼接符有sql注入的风险,所以慎重使用

    <select id="getByUserName" parameterType="string" resultType="users">
        select <include refid="allCloums"></include>
        from users where username like '%${value}%'
    </select>

日志sql输出:

select id,userName,birthday,sex,address from users where username like ‘%张三%’

2.字符串拼接法

    <select id="getByUserName" parameterType="string" resultType="users">
        select <include refid="allCloums"></include>
        from users where username like "%"#{userName}"%" 
    </select>

日志sql输出:

select id,userName,birthday,sex,address from users where username like “%”?"%"

3. MySQL拼接函数concat()

    <select id="getByUserName" parameterType="string" resultType="users">
        select <include refid="allCloums"></include>
        from users where username like concat("%", #{value}, "%")
    </select>

日志sql输出:

select id,userName,birthday,sex,address from users where username like concat("%", ?, “%”)

#{}和${}的区别

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

解决java实体类的属性名与数据库字段名不一致

使用resultMap:

    <resultMap id="bookMap" type="book">
        <id property="id" column  = "bookid"></id>
        <result property="name" column="bookname"></result>
    </resultMap>
    <select id="getAllByResultMap" resultMap="bookMap">
        select bookid,bookname from book
    </select>
发布了46 篇原创文章 · 获赞 16 · 访问量 2640

猜你喜欢

转载自blog.csdn.net/qq_43598138/article/details/103787790
今日推荐