Myabtis简单入门使用

本文详细介绍MyBatis框架的基本概念、配置与使用方法,包括环境搭建、CRUD操作及性能优化技巧,适合初学者快速掌握MyBatis的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MyBatis入门

1.Mybtatis简介

1.1 MyBatis的介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
Mybtais是一个持久层框架,底层是对JDBC的封装,支持普通的sql查询,但是sql语句需要自己写,并且MyBatis不支持自动建表,需要自己先准备好数据库和表

1.2 ORM框架
  • ORM:是指对象关系映射,是关系型数据库到实体对象之间的映射
  • JPA:本身是一种ORM规范,不是ORM框架,而Hibernate是其中一种实现
  • Hibernate:是一个完整的ORM框架,常规CRUD我们不需要写一句SQL,底层封装比较多,所以开发速度快,但是性能方面要比我们写原生sql性能要低的多
  • MyBatis:并不是一个完整的ORM框架,因为我们还需要自己去写全部SQL,它的性能要比Hibernate快。

2.Mybatis完成简单的CRUD操作

  • 通过Mybatis完成CRUD的操作步骤如下:
    1.创建数据库和建表:Mybatis不能自动建表,所以需要我们手动先把数据库和表准备好
    2.准备一个普通的项目
    3.导入Mybatis需要的jar包: mybatis的核心包、mybatis的依赖包、数据库的驱动包
    4.准备domain
    5.准备好配置文件:mybatis的核心配置、写sql的xml配置文件
    6.测试:需要使用SqlSessionFactory、SqlSession两个核心对象
    前面四个步骤很简单,主要将一下mybatis的配置,已经curd的核心代码
2.1 mybatis配置文件
2.1.1 mybatis的核心配置文件: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:配置,是mybatis核心配置文件的根标签-->
    <configuration>
        <!--配置properties文件,resource属性会告诉核心配置文件直接去项目的resources文件夹下去找-->
        <properties resource="jdbc.properties"></properties>

        <!--设置别名:typeAliases可以设置多个别名,在这里设置了别名,可以在sql的xml中使用-->
        <typeAliases>
            <!--每一个typeAlias表示一个别名,type是类的完全限定名,alias是别名,不区分大小写-->
            <!--<typeAlias type="cn.lqq.domain.Product" alias="product"/>-->
            <!--也可以使用package标签对整个domain包下的类都进行别名设置,别名默认是表名-->
            <package name="cn.lqq.domain" />
        </typeAliases>
        <!--environments:环境们,在这里可以配置多个环境,default属性表示默认的环境,一般默认的都是开发环境-->
        <environments default="development">
            <!--environment:环境,id是只是一个名称,这里表示默认的开发环境是这个-->
            <environment id="development">
                <!--transactionManager:事务管理,type类型有两个值:JDBC/MANAGED
                        JDBC:表示JDBC原生的事务管理进行提交和回滚
                        MANAGED:表示不做任何事情,就是没有事务
                    dataSource:表示数据库,连接池,type类型有三个值:UNPOOLED/POOLED/JNDI
                    UNPOOLED:没有用到连接池,没有请求都会开启和关闭连接
                    POOLED:底层就是使用的JDBC连接池实现的
                    JNDI:这个是使用spring框架的时候,使用这个,没有使用到spring框架就使用POOLED
                -->
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
       <!--在这里面配置连接数据库的属性,这里要读取jdbc.properties中的值,所以要配置一下-->
                    <property name="driver" value="com.mysql.jdbc.Driver" />
                    <property name="url" value="jdbc:mysql:///mybatis" />
                    <property name="username" value="root" />
                    <property name="password" value="123456" />
                </dataSource>
            </environment>
        </environments>

		<!---用来配置mybatis映射器,mapper 对应的是每一个映射文件,就是要读取书写sql的xml文件-->
        <mappers>
        	<!--这个路径表示放在资源文件夹的根目录下,如果放在其他文件夹下,直接写上包名加文件名-->
            <mapper resource="Product_Sql.xml"></mapper>
        </mappers>
    </configuration>
2.1.2 书写sql的xml配置文件:Product_Sql.xml

使用mybatis是需要自己手动写sql的,我们使用一个xml的配置文件用来写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">
    <!--这个配置文件专门用来写sql的,而且是关于product的sql,namespace属性就his一个命名空间
        通过namespace属性和sql的id属性,我们可以定位找到具体的sql语句
    -->
    <mapper namespace="cn.lqq.dao.ProductSql">
    
        <!--查询一条数据的sql:parameterType是在参数的类型,如果有参数就写,没有参数就不写
          resultType:指返回值的类型,注意这里是指每一条数据的返回类型,并不是结果集的返回类型
          Mybatis的核心配置文件中有设置别名,所以下面有的地方cn.lqq.domain.Product直接用别名product
        -->
        <select id="findOne" parameterType="long" resultType="product">
            select * from product where id=#{id}
        </select>
        <select id="findAll" resultType="product">
            select * from product
        </select>
        <!--添加数据的sql:如果添加的时候拿到主键的值,需要做以下配置
            useGeneratedKeys:表示在添加的时候是否需要拿到主键的值
             keyProperty:是指domain类中主键的属性名
             keyColumn:是指数据库表中主键的列名称
         -->
        <insert id="save" parameterType="cn.lqq.domain.Product"
                useGeneratedKeys="true" keyProperty="id" keyColumn="id" >
            insert into product (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
            values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
        </insert>
        <!--修改数据的sql-->
        <update id="update" parameterType="cn.lqq.domain.Product">
            update product set productName=#{productName},dir_id=#{dir_id},salePrice=#{salePrice},supplier=#{supplier},
        brand=#{brand},cutoff=#{cutoff},costPrice=#{costPrice} where id=#{id}
        </update>
		<!--删除一条数据-->
        <delete id="delete" parameterType="long">
            delete from product where id=#{id}
        </delete>
    </mapper>
2.2 完成curd的操作
  • 查询所有的测试,直接使用junit4单元测试进行测试,步骤是:
    1.读取mybatis的核心配置文件
    2.创建SqlSessionFactory对象
    3.获取到SqlSession对象
    4.执行sql语句
 @Test
    public void testFindOne()throws Exception{
        //1.读取mybatis的核心配置文件
        Reader reader = Resources.getResourceAsReader("mybatis_configuration.xml");
        //2.创建SqlSesssionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
        //3.创建SqlSession对象
        SqlSession session = factory.openSession();
        //4.执行sql
        Product product = session.selectOne("cn.lqq.dao.ProductSql.findOne", 1L);
        System.out.println(product);
    }
2.2.1 抽取工具类

上面的操作步骤对增删改查都适用,只有第四步执行sql的方法可能不一样,所以对于上面三个重复的代码,我们可以抽取一个工具类获取到sqlSession对象,然后就可以通过该对象调用具体方法执行curd
因为SqlSessionFactory对象,是一个应用对应一个factory对象,所以最好设置成单例模式,把他放在静态代码块中赋值,就保证了它是一个单例的对象

public class MyBatiUtils {
    private static SqlSessionFactory factory;
    static{
        try {
            //读取核心配置文件
            Reader reader = Resources.getResourceAsReader("mybatis_configuration.xml");
            factory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession openSession(){
        return factory.openSession();
    }
}
2.2.2 完善dao层接口
public interface IProductDao {
	//查询所以数据
    List<Product> findAll();
    //查询一条数据
    Product findOne(Long id);
    //添加数据
    void save(Product product);
    //修改数据
    void updata(Product product);
    //删除数据
    void delete(Long id);
}
2.2.3 完成dao层接口的实现

需要注意的点是:
1.通过sqlSession执行sql操作的时候,要通过sql的xml配置文件的namespace和具体sql的id来定位到我们要执行的sql语句
2.查询没有事务,但增删改操作必须添加事务才能操作成功
3.执行sql语句的代码最好放在try…catch块中,因为可能定位不到sql语句

public class ProductDaoImpl implements IProductDao {

    //因为下面的cn.lqq.dao.ProductSql是命名空间,同一个domain都是一样的,可以提取供公共字段
    private static final String NAMESPACE = "cn.lqq.dao.ProductSql.";

    @Override
    public List<Product> findAll() {
        //工具类中已经try..catch了,所以这里不用放在try块里面
        SqlSession session = MyBatiUtils .openSession();
        try {
            //这里之所以要try..catch,是因为下面可能会出现找不到sql语句,
//            return session.selectList("cn.lqq.dao.ProductSql.findAll");
            return session.selectList(NAMESPACE+"findAll");
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Product findOne(Long id) {
        SqlSession session = MyBatiUtils .openSession();
        try {
            return session.selectOne(NAMESPACE+"findOne",id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void save(Product product) {
        SqlSession session = MyBatiUtils .openSession();
        try {
            session.insert(NAMESPACE+"save",product);
            //对于增删改要添加事务,否则提交不了
            session.commit();
        } catch (Exception e) {
            session.rollback();
            e.printStackTrace();
        }finally {
            session.close();
        }
    }

    @Override
    public void updata(Product product) {
        SqlSession session = MyBatiUtils .openSession();
        try {
            session.update(NAMESPACE+"update",product);
            session.commit();
        } catch (Exception e) {
            session.rollback();
            e.printStackTrace();
        }finally {
            session.close();
        }
    }

    @Override
    public void delete(Long id) {
        SqlSession session = MyBatiUtils .openSession();
        try {
            session.delete(NAMESPACE+"delete",id);
            session.commit();
        } catch (Exception e) {
            session.rollback();
            e.printStackTrace();
        }finally {
            session.close();
        }
    }
}
2.2.4 在单元测试类中对象dao层进行测试
public class ProductDaoTest {
   private IProductDao dao = new ProductDaoImpl();

    @Test
    public void testFindAll()throws Exception{
        dao.findAll().forEach(e-> System.out.println(e));
    }

    @Test
    public void testFindOne()throws Exception{
        Product product = dao.findOne(1L);
        System.out.println(product);
    }

    @Test
    public void testSave()throws Exception{
        Product product = dao.findOne(1L);
        product.setId(null);
        product.setProductName("雷蛇");
        dao.save(product);
        System.out.println(product);
    }

    @Test
    public void testUpdate()throws Exception{
        Product product = dao.findOne(21L);
        product.setProductName("雷蛇2");
        dao.updata(product);
    }
    
    @Test
    public void testDelete()throws Exception{
        dao.delete(21L);
    }
}

3.Mybatis三大核心对象

3.1 SqlSessionFactoryBuilder

这个对象存在的主要目的就是为了创建SqlSessionFactory对象。这里使用了构造者的设计模式来获取到SqlSessionFactory对象。
一旦你创建了SqlSessionFactory后,这个SqlSessionFactoryBuilder类就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是本地方法变量)。

3.2 SqlSessionFactory

一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。所以在一个应用中应该只有一个SqlSessionFactory对象,这个对象在你的应用中应该设置为单例模式或静态代理模式

3.3 SqlSession

每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。
绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。
这是一个轻量级的对象,通过这个对象可以完成数据库的CRUD操作

4.Mybatis使用的细节

4.1 添加数据时拿到主键

添加数据的时候,主键采用了自动递增的策略,所以添加的时候可以不用输入主键值,数据添加到数据库中以后,数据库会自动生成主键的值,所以在添加数据的时是拿不到主键字段的值的,注意JPA不一样,JPA的EntityManager对象中内置了一级缓存,所以在在添加的时候可以拿到主键的字段值,但是这样会消耗性能。
在Mybatis中添加数据默认是拿不到主键的值的,但如果要拿到刚刚添加的那一条数据的主键的值,可以进行如下配置:
在insert标签中添加下面三个属性useGeneratedKeys,keyProperty,keyColumn

<!--如果添加的时候拿到主键的值,需要做以下配置
          useGeneratedKeys:表示在添加的时候是否需要拿到主键的值
           keyProperty:是指domain类中主键的属性名
           keyColumn:是指数据库表中主键的列名称
-->
<insert id="save" parameterType="cn.lqq.domain.Product"
       useGeneratedKeys="true" keyProperty="id" keyColumn="id" >
   insert into product (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
   values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
4.2 Mybatis中为一个类取别名

Mybatis别名有两种:
1.内置别名,这个可以在Mybatis的文档中查看,基本数据类型和包装类都是Mybatis的内置别名,对于内置的别名,我们可以直接使用。需要注意的一点是,别名不区分大小写,所以所有的基本类型在前面都会加上_,例如:int的别名是_int,long的别名是_long
2.自定义别名:我们在xml文件中写sql的时候,参数和返回值的类型需要写上完全限定名,这里可以直接自定义定义一个别名,自定义别名是在mybatis的核心配置文件中使用typeAliases标签,在这个标签里面可以使用typeAlias子标签定义多个别名。
typeAlias:可以对一个具体的类设置别名。
package :可以对一个包下的所有的类都设置别名,而别名默认就是类名。

<!--设置别名:typeAliases可以设置多个别名,在这里设置了别名,可以在sql的xml中使用-->
<typeAliases>
     <!--每一个typeAlias表示一个别名,type是类的完全限定名,alias是别名,不区分大小写-->
     <typeAlias type="cn.lqq.domain.Product" alias="product"/>
     <!--也可以使用package标签对整个domain包下的类都进行别名设置,别名默认是表名-->
     <package name="cn.lqq.domain" />
</typeAliases>

然后在其他使用到cn.lqq.domain.Product的地方直接使用它的别名product
注意:在MyBatis的核心配置文件的根标签configuration下面,所有的标签顺序都是固定的,不能随便写,写错了会报错

4.3 列名与属性名不对应如何解决

当我们数据库表中的列名称和我们实体类的属性名称不匹配的时候,我们在进行CRUD操作的时候,类中的字段到表中的列的自动映射就会失败,这时我们就需要对列名和属性名不一致的进行手动映射。
resultMap标签用来手动设置表中列名和类中字段的映射关系。
id子标签用来设置主键字段的映射
result子标签用来设置其他字段的映射关系

<!--当我们类中的字段名和表中的列名称不一样时,我们可以设置映射,不过映射完在下面要配置-->
 <resultMap id="productMap" type="cn.lqq.domain.Product">
   		  <!--如果映射主键字段使用的是id标签,映射的是其他字段使用result标签
      			   property是类的属性名, column是表中的列名称-->
   		  <id property="id" column="id"></id>
   		  <!--对于增改直接在取值的时候修改成dirId就可以了,可以不用引用-->
     	  <result property="dirId" column="dir_id"></result>
 </resultMap>
   <!--parameterType是在参数的类型,如果有参数就写,没有参数就不写
     resultType:指返回值的类型,注意这里是指每一条数据的返回类型,并不是结果集的返回类型 -->
<select id="findOne" parameterType="long" resultMap="productMap">
   		 select * from product where id=#{id}
</select>
4.4 #与$的区别

我们在写sql语句的时候,如果有参数,传值的时候使用的是#{},这里也可以使用${}这个取值,#与 $的区别是:

$:只能获取的是传过来的对象的一个属性(拼接字符串),这种方式有sql注入的问题,能不能使用就不使用。
#:即可以获取传过来的一个值,也可以获取传过来的对象的属性(占位),可以防止sql注入,而且性能更好,如果#不能使用,我们才去使用 $
如下:id是通过#{} 取值的,也可以使用 ${id} 取值,不过不建议使用

<delete id="delete" parameterType="long">
   	 delete from product where id=#{id}
</delete>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值