mybatis基础1

Posted mslog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis基础1相关的知识,希望对你有一定的参考价值。

1、mybatis的框架

 解释:

1、  mybatis配置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编程中对结果的解析处理过程。

2、mybatis所需的jar和依赖的jar包

2.1下载mybatis

  mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases

  目录结构:

mybatis-3.2.7.jar----mybatis的核心包

lib----mybatis的依赖包

mybatis-3.2.7.pdf----mybatis使用手册

3、搭建mybatis工程

3.1加入mybatis核心包、依赖包、数据驱动包。

3.2配置log4j.properties,与classpath下

因为mybatis默认使用log4j作为输出日志信息。

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

 

3.3创建SqlMapConfig.xml

在classpath下创建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>
    <!--和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
        <!--使用jdbc事务管理-->
            <transactionManager type="JDBC" />
        <!--数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybaits?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="admin" />
            </dataSource>
        </environment>
    </environments>
</configuration>

 

注意:SqlMapConfig.xml是mybatis核心配置文件,上边文件的配置内容为数据源、事务管理和连接池。

4、小实例

4.1po类

Po类作为mybatis进行sql映射使用,po类通常与数据库表对应,User.java如下:

数据库的表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT \'用户名称\',
  `birthday` date DEFAULT NULL COMMENT \'生日\',
  `sex` char(1) DEFAULT NULL COMMENT \'性别\',
  `address` varchar(256) DEFAULT NULL COMMENT \'地址\',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;

 

对应的user的po类

public class User {
    private int id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

 

4.2创建sql映射文件

在classpath下的sqlmap目录下创建sql映射文件Users.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="test">
</mapper>

 

namespace:类似于c++中的namespace和Java中的package,用于隔离sql语句

4.3加载映射文件

mybatis框架需要加载映射文件,将Users.xml添加在SqlMapConfig.xml,如下:

<mappers>
        <mapper resource="sqlmap/User.xml"/>
</mappers>

 

4.3实现提供ID查询用户

4.3.1修改映射文件

在user.xml中添加:

<!-- 根据id获取用户信息 -->
    <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
        select * from user where id = #{id}
    </select>

 

 

注意:

1、id:sql语句唯一表示
2、parameterType:指定传入参数类型,对应pojo属性的类型
3、resultType:返回结果类型
4、#{}占位符,起到站位的作用,如果传入的是基本类型(string、long、int、boolean、float等),
    那么#{}中的变量名称可以是随意写,一般写属性

4.3.2测试程序

public class UserTest {
    
    @Test
    public void testFindUserById() throws Exception{
        String resource = "SqlMapConfig.xml";
        //通过流将核心配置文件读取进来
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //通过核心配置文件输入流来创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //通过工厂创建会话
        SqlSession session = factory.openSession();
        //第一个参数:所调用的sql语句:namespece.+sql的id
        User user= session.selectOne("test.findUserById", 1);
        System.out.println(user);
        session.close();
    }
}

 

4.4根据用户名查询用户信息

4.4.1修改映射文件

在user.xml中添加:

    <select id="findUserByUserName" parameterType="java.lang.String" resultType="com.wang.pojo.User">
        SELECT * from user where  username like \'%${value}%\'
    </select>

 

注意:

1、如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所映射的文件一个配置成集合范型的类型
2、${}拼接符,字符串原样拼接,如果传入的是基本类型(string、long、int、boolean、float等),
  那么%{}中的变量名称必须是value
  但有sql注入的风险

4.4.2测试程序

    @Test
    public void testFindUserByUserName()throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = factory.openSession();
        
        List<User> selectList= sqlSession.selectList("test.findUserByUserName", "王");
        System.out.println(selectList);
    }

 

4.5总结

4.5.1#{}和${}

a、#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,

  #{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

#{}:如果传入的pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....

b、${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,

  如果parameterType传输单个简单类型值,${}括号中只能是value。

  ${}:如果传入的pojo类型,那么${}中的变量名称必须是pojo中对应的属性.属性.属性.....

4.5.2parameterType和resultType

parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。

resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。

4.5.2selectOne和selectList

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常。

selectList可以查询一条或多条记录。

 

5、增删改查的实现

5.1增加(并且返回自增的主键id值)

5.1.1  映射文件:

在user.xml中添加:

    <insert id="insertUser" parameterType="com.wang.pojo.User">
    <!--
         执行SELECT LAST_INSERT_ID()数据库函数,返回自增主键
         keyProperty:将返回的主键放入传入参数的Id中保存
         order:当前函数相对于insert语句的执行顺序,在insert前是BEFORE之后是AFTER
         resultType:ID的类型,就是keyProperty中的类型
     -->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>

 

注意:添加selectKey实现将主键返回

keyProperty:返回的主键存储在pojo中的哪个属性

order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after

resultType:返回的主键是什么类型

LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。

5.1.2测试程序:

    //自动开启事务,但是要自己手动提交事务
    @Test
    public void testInsertUser()throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        User user = new User();
        user.setSex("1");
        user.setAddress("北京");
        Date date = new Date();
        user.setBirthday(date);
        user.setUsername("大江");
        System.err.println(user.getId());

        session.insert("test.insertUser", user);
        //提交事务(没有不插入数据库)
        session.commit();
        System.err.println(user.getId());
        session.close();
    }

 

注意:mybatis是自动开启事务,但是要手动提交事务

衍生:UUID的主键获取

<insert  id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey resultType="java.lang.String" order="BEFORE" 
keyProperty="id">
select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address) 
         values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>

 

使用的是 order="BEFORE" 和select uuid()

5.2 删除用户

5.2.1  映射文件:

在user.xml中添加:

    <delete id="deleteUserById" parameterType="java.lang.Integer">
        delete from user where id=#{id}
    </delete

 

5.2.2测试

    @Test
    public void testDeleteUserById()throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        session.delete("test.deleteUserById", 29);
        session.commit();
        session.close();
    }

 

5.3修改

5.3.1修改user.xml

    <update id="updateById" parameterType="com.wang.pojo.User">
        update user set username=#{username} where id=#{id}
    </update>

 

5.3.2添加测试

    @Test
    public void testUpdateUserById()throws Exception{
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        User user = new User();
        user.setId(28);
        user.setUsername("lllll");
        session.update("test.updateById", user);
        session.commit();
        session.close();
    }

 

SqlSession在讨论

6.1SqlSession的使用范围

SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。

通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

6.2SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,

因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

6.3SqlSessionFactory

SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,

一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

6.4SqlSession

SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作方法。

         每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

         打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:

         SqlSession session = sqlSessionFactory.openSession();

         try {

                  // do work

         } finally {

                session.close();

         }

 

7 DAO层的开发:

7.1原生(自定义实现)DAO层的开发

7.1.1 sql映射文件

<?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:命名空间,做sql隔离 -->
<mapper namespace="test">
    <!-- 
    id:sql语句唯一表示
    parameterType:指定传入参数类型,对应pojo属性的类型
    resultType:返回结果类型
    #{}占位符,起到站位的作用,如果传入的是基本类型(string、long、int、boolean、float等),
    那么#{}中的变量名称可以是随意写,一般写属性
    -->
    <select id="findUserById" parameterType="java.lang.Integer" resultType="com.wang.pojo.User">
        SELECT * from user WHERE id =#{id}
    </select>
    <!-- 
        如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所映射的文件一个配置成集合范型的类型
         ${}拼接符,字符串原样拼接,如果传入的是基本类型(string、long、int、boolean、float等),
    那么%{}中的变量名称必须是value
    注意:有sql注入的风险
     -->
    <select id="findUserByUserName" parameterType="java.lang.String" resultType="com.wang.pojo.User">
        SELECT * from user where  username like \'%${value}%\'
    </select>
</mapper>

 

7.1.2 dao层

public interface UserDao {
    
    public User findUserById(Integer id);
    
    public List<User> findUserByName(String userName);

}

 

dao层的实现层

public class UserDaoImpl implements UserDao {

    private SqlSessionFactory factory;
    
    public UserDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

    @Override
    public User findUserById(Integer id) {
        //sesion是线程不安全的,最佳在方法体内
        SqlSession session = factory.openSession();
        User user = session.selectOne("test.findUserById", id);
        return user;
    }

    @Override
    public List<User> findUserByName(String userName) {
         SqlSession sqlSession = factory.openSession();
         List<User> selectList= sqlSession.selectList("test.findUserByUserName",userName);
         return  selectList;
    }
}

 

7.1.3测试

public class UserDaoTest {
    
    private SqlSessionFactory factory;
    
    @Before
    public void setUp()throws Exception {
        String resource = "SqlMapConfig.xml";
        //通过流将核心配置文件读取进来
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //通过核心配置文件输入流来创建会话工厂
        factory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    @Test
    public void findUserById() throws Exception{
        UserDao userDao = new UserDaoImpl(factory);
        System.out.println(userDao.findUserById(1));    
    }
    
    @Test
    public void findUserByName() throws Exception{
        UserDao userDao = new UserDaoImpl(factory); 
        List<User> users =userDao.findUserByName("王");
        System.out.println(users);
    }

}

 

存在的问题:

原始Dao开发中存在以下问题:

1、Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法

2、 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不利于开发维护。

 

7.2 Mapper动态代理方式   

7.2.1开发规范

Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发需要遵循以下规范:

  1、  Mapper.xml文件中的namespace与mapper接口的类全路径相同

  2、  Mapper接口方法名和Mapper.xml中定义的每个statement的id相同(sql语句的id)

  3、  Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

  4、  Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

注意:mapper类名与mapper映射文件名相同

7.2.2Mapper.xml(映射文件)

  定义mapper映射文件UserMapper.xml(内容同Users.xml),需要修改namespace的值为 UserMapper接口路径

将UserMapper.xml放在classpath 下mapper目录下。

<?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="cn.itcast.mybatis.mapper.UserMapper">
<!-- 根据id获取用户信息 -->
    <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
        select * from user where id = #{id}
    </select>
<!-- 自定义条件查询用户列表 -->
    <select id="findUserByUsername" parameterType="java.lang.String" 
            resultType="cn.itcast.mybatis.po.User">
       select * from user where username like \'%${value}%\' 
    </select>
<!-- 添加用户 -->
    <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        select LAST_INSERT_ID() 
    </selectKey>
      insert into user(username,birthday,sex,address) 
      values(#{username},#{birthday},#{sex},#{address})
    </insert>

</mapper>

 

7.2.3Mapper.java(接口文件)

Public interface UserMapper {
    //根据用户id查询用户信息
    public User findUserById(int id) throws Exception;
    //查询用户列表
    public List<User> findUserByUsername(String username) throws Exception;
    //添加用户信息
    public void insertUser(User user)throws Exception; 
}

 

接口定义有如下特点:

  1、  Mapper接口方法名和Mapper.xml中定义的statement的id相同

  2、  Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同

  3、  Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同

7.2.4 加载UserMapper.xml文件

        <mapper class="com.wang.mapper.UserMapper"/>

 

注意:

使用类扫描的方式引入Mapper接口
1、接口名称和映射文件名称除扩展名外要完全相同
2、接口和映射文件要放在同一个目录下

或:

<package name="com.wang.mapper"/>

 

注意:

使用包扫描的方式批量引入Mapper接口
1、接口名称和映射文件名称除扩展名外要完全相同
2、接口和映射文件要放在同一个目录下

7.2.5测试

public class UserMapperTest {
    private SqlSessionFactory factory;
    
    @Before
    public void setUp()throws Exception {
        String resource = "SqlMapConfig.xml";
        //通过流将核心配置文件读取进来
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //通过核心配置文件输入流来创建会话工厂
        factory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    @Test
    public void findUserById() throws Exception{
        SqlSession session = factory.openSession();
        //通过getMapper实例化接口
        UserMapper userMapper = session.getMapper(UserMapper.class);
        
        User user= userMapper.findUserById(1);
        System.err.println(user);
    }
    
    @Test
    public void findUserByUserName() throws Exception{
        SqlSession session = factory.openSession();
        //通过getMapper实例化接口
        UserMapper userMapper = session.getMapper(UserMapper.class);
        
        List<User> users= userMapper.findUserByUserName("王");
        System.err.println(users);
    }
    
    @Test
    public void insertUser() throws Exception{
        SqlSession session = factory.openSession();
        //通过getMapper实例化接口
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = new User();
        user.setAddress("南京");
        user.setSex("1");
        user.setBirthday(new Date());
        user.setUsername("孙");
        userMapper.insertUser(user);
        session.commit();
    }
}

 

7.3总结

  1、selectOne和selectList

  动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定

如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

  2、 namespace

  mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,

输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

 

8 SqlMapConfig.xml配置文件

8.1    配置内容

 SqlMapConfig.xml中配置的内容和顺序如下:

   properties(属性)

  settings(全局配置参数)

  typeAliases(类型别名)

  typeHandlers(类型处理器)

  objectFactory(对象工厂)

  plugins(插件)

  environments(环境集合属性对象)

    environment(环境子属性对象)

      transactionManager(事务管理)

      dataSource(数据源)

  mappers(映射器)

8.2 properties

SqlMapConfig.xml可以引用java属性文件中的配置信息如下:

  在classpath下定义db.properties文件,

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybaits?characterEncoding=utf-8
jdbc.username=root
jdbc.password=admin

 

SqlMapConfig.xml引用如下:

    <environments default="development">
        <environment id="development">
        <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
        <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>

 

注意: MyBatis 将按照下面的顺序来加载属性:

  1、在 properties 元素体内定义的属性首先被读取。

  2、然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。

 

8.3  typeAliases(类型别名)

8.3.1 mybatis支持别名:

别名

映射的类型

_byte

byte

_long

以上是关于mybatis基础1的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis动态SQL标签用法

mybatis动态sql片段与分页,排序,传参的使用

[vscode]--HTML代码片段(基础版,reactvuejquery)

mybatis学习(39):动态sql片段

SSM-MyBatis-05:Mybatis中别名,sql片段和模糊查询加getMapper

MyBatis高级特性

(c)2006-2024 SYSTEM All Rights Reserved IT常识