Mybatis(1)

ORM

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xxs7ZE2Q-1671874123591)(笔记.assets/1665191124835.png)]

ORM:对象关系映射。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AgSQJ3bi-1671874123592)(笔记.assets/1665191531727.png)]

问题:我们之前使用JDBC是否是面向对象的操作?

保存数据:把数据从对象中逐个取出,填入sql语句对应的位置。执行sql。

读取数据:从sql查询的结果集中取出数据,设置到对象对应的位置。

如果程序本身已经知道列名和对象属性名之间的对应关系,程序是否可以自己完成JDBC的基本操作?

于是就有了各种ORM框架…

  • Hibernate 强大的ORM框架。全自动化框架。
  • MyBatis 最流行的ORM框架。半自动化框架。
  • 其他…

MyBatis框架

Helloworld

官方网站:https://mybatis.net.cn/

[1]在项目中添加MyBatis的依赖

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

不要忘记JDBC的依赖。

[2]添加对应的配置文件,构建对应的SqlSessionFactory对象。

2.1在项目的main/resources下添加配置文件:mybatis-config.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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/crm?serverTimezone=GMT%2B8&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="root123"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

这个配置文件很明显是配置连接数据库的相关属性。

2.2准备实体类和数据表

create table user(
	id bigint not null primary key auto_increment,
	username varchar(200),
	userage int,
	usertel char(11)
)
/**
 * @author 戴着假发的程序员
 * @company 起点编程
 * 2022/10/8 9:31
 */
public class User {
    private Long id;
    private String username;
    private int userage;
    private String usertel;
}

tisp: 这里确保类的属性名和数据表的列名完全一致。

2.3 在main/resources/maps下添加配置文件: UserMapping.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 相当于当前文件的唯一标志 -->
<mapper namespace="com.qidian.UserMapping">
    <!-- 这里是查询的sql语句的配置 -->
    <select id="selectUser" resultType="com.qidian.pojo.User">
        select * from user where id = #{id}
    </select>
</mapper>

在mybatis-config.xml中添加配置:

<!-- 注册映射文件 -->
<mappers>
    <mapper resource="maps/UserMapping.xml"/>
</mappers>

2.4 在测试类中创建SqlSessionFactory对象

对于MyBatis来说,和数据库的一次链接就是一个会话。于是在MyBatis中就有一个SqlSession的概念。
SqlSession就相当于之前的一个Connection对象。
我们要得到SqlSession对象,就需要SqlSessionFactory。
/**
 * @author 戴着假发的程序员
 * @company 起点编程
 * 2022/10/8 9:39
 */
public class MyBatisTest {
    @Test
    public void testGetSqlSessionFactory() throws IOException {
        // 主配置文件的位置
        String resource = "mybatis-config.xml";
        // 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        System.out.println(sqlSessionFactory);
    }
}

[3]获取SqlSession,执行sql语句

可以通过SqlSessionFactory获取一个sqlSession

    @Test
    public void testHelloword() throws IOException {
        // 主配置文件的位置
        String resource = "mybatis-config.xml";
        // 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        System.out.println(sqlSessionFactory);
        // 获取一个SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 通过sqlsession执行sql语句
        Object user = sqlSession.selectOne("com.qidian.UserMapping.selectUser", 2);
        User u = (User) user;
        System.out.println(u);
    }

执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SjqDzLR-1671874123592)(笔记.assets/1665193620813.png)]

我们不需要在创建connection,Statement,获取数据放入对象等等操作。

MyBatis可以执行sql语句,并且直接返回对象。

程序的说明:

配置文件mybatis-config.xml 主要用来配置MyBatis的基本配置,比如数据库连接的相关信息,这个配置配置文件主要用来生成SqlSessionFactory。

配置文件UserMapping.xml为User实体类和user数据表之间的映射文件,主要用来配置要执行的sql语句。这个配置文件要注册到mybatis-config.xml文件中。

通过SqlSessionFactory获取一个SqlSession,通过SqlSession就可以执行配置在映射文件中的sql语句。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnKS3NsI-1671874123593)(笔记.assets/1665194669477.png)]

执行sql语句的时候,需要指明sql,sql的标志是 映射文件的namspace+sql语句的id。

执行sql语句之后MyBatis会根据sql语句中设置的resultType封装一个对象,并且将数据放入对象中。

MyBatis的CRUD

MyBatis是将sql语句和java程序分离的。

sql语句是配置在映射文件中的。自动完成参数设置和结果集封装。

提供的SqlSession对象有大量可以使用的API用来执行JDBC的基本操作。

[1]通过id查询用户

在映射文件中配置sql:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z5XDlT6J-1671874123593)(笔记.assets/1665194964198.png)]

在一个映射文件中可以配置多个sql语句,查询语句的标签是select

每一个sql语句都应该有id,这个id应该在当前的映射文件中唯一标志当前的sql语句。

查询语句都是有resultType或者resultMap的配置,主要用来配置查询结果的返回值类型。

sql语句中可以使用#{xxx}来做占位符。当一个sql语句只有一个参数的时候,#{这里的可以随意}

[2]添加用户操作

准备sql语句:在UserMapping中添加sql配置:

<!-- 添加用户 -->
<insert id="saveUser" parameterType="com.qidian.pojo.User">
    insert  into user(username,usertel,userage) values(#{username},#{usertel},#{userage})
</insert>

添加的sql语句要使用insert标签,没有resultType配置,但是要配置属性parameterTyep,我们这里配置的是实体类的全限定类名。

sql语句中的参数要写实体对象的属性名。 #{属性名}

测试程序:

准备一个Before方便测试:

private SqlSessionFactory sqlSessionFactory = null;

@Before // 在单元测试之前执行
public void before() throws IOException {
    // 主配置文件的位置
    String resource = "mybatis-config.xml";
    // 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    // 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

添加测试程序

    @Test
    public void testInsert(){
        // 准备实体对象
        User user = new User();
        user.setUsername("鸣人");
        user.setUserage(19);
        user.setUsertel("13013013030");
        // 获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行sql语句
        int result = sqlSession.insert("com.qidian.UserMapping.saveUser", user);
        // MyBatis不自动提交事务,增删改操作需要我们手动的提交事务
        sqlSession.commit();
        System.out.println(result);
    }

[3]修改用户操作

添加sql语句:

    <!-- 修改用户 -->
    <update id="updateUser" parameterType="com.qidian.pojo.User">
        update user set username=#{username},userage=#{userage},usertel=#{usertel}
        where id=#{id}
    </update>

测试程序:

    @Test
    public void testUpdate(){
        // 获取一个SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 查询一个用户
        User user = sqlSession.selectOne("com.qidian.UserMapping.selectUser", 2);
        // 修改信息
        user.setUsertel("12212212222");
        // 保存修改的信息
        int update = sqlSession.update("com.qidian.UserMapping.updateUser", user);
        // 不要忘记提交事务
        sqlSession.commit();
        System.out.println(update);
    }

[4]删除用户信息

添加sql:

<!-- 删除用户 -->
<delete id="deleteUser" parameterType="long">
    delete from user where id = #{xxx}
</delete>

测试程序:

    @Test
    public void testDelete(){
        // 获取一个SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 根据ID删除用户信息
        int update = sqlSession.update("com.qidian.UserMapping.deleteUser", 4L);
        // 不要忘记提交事务
        sqlSession.commit();
        System.out.println(update);
    }

[5]查询全部

添加sql语句:

<!-- 查询全部 -->
<!-- 即便我们查询的而是list,这里的resultType要写list中的类型 -->
<select id="selectAll" resultType="com.qidian.pojo.User">
    select * from user
</select>

测试程序:

    @Test
    public void testSelectAll(){
        // 获取一个SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 查询全部的操作
        List<User> list = sqlSession.selectList("com.qidian.UserMapping.selectAll");
        System.out.println(list);
    }

列名和属性名不一致的情况

MyBatis自动完成了映射关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMSZ8wBg-1671874123594)(笔记.assets/1665196334060.png)]

因为我们这里的列名和属性名完全一致,所以可以自动映射。

如果不一致可能会出现问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lbL6H8Km-1671874123594)(笔记.assets/1665196476148.png)]

添加映射文件:SourceMapper.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 相当于当前文件的唯一标志 -->
<mapper namespace="com.qidian.SourceMapper">
    <!-- 查询全部 -->
    <!-- 即便我们查询的而是list,这里的resultType要写list中的类型 -->
    <select id="selectAll" resultType="com.qidian.pojo.Source">
        select * from source
    </select>
</mapper>

将映射文件注册到mybaits-config.xml中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lcvIUKn6-1671874123595)(笔记.assets/1665196579411.png)]

测试程序:

@Test
public void testSelectAllSource(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    List<Object> list = sqlSession.selectList("com.qidian.SourceMapping.selectAll");
    System.out.println(list);
}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7erOZ0Rk-1671874123595)(笔记.assets/1665196687929.png)]

由于MyBatis认为属性sourceName在数据表source中没有对应的列,所以就不设置任何值。

解决方案1:给查询结果的列名设置别名。

修改sql:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1ltqd1d-1671874123596)(笔记.assets/1665196794740.png)]

解决方案2:配置一个resultMap,将查询结果的返回值类型设置为对应的resultMap

在映射文件中添加resultMap

    <!-- 添加一个结果映射关系 (配置数据表的列和实体类属性之间的对应关系)-->
    <resultMap id="baseResultMap" type="com.qidian.pojo.Source">
        <!-- 配置主键映射  一定要配置列名和属性名,类型是可以自动识别的-->
        <id column="id" property="id" javaType="java.lang.Integer"/>
        <!-- 其他属性配置 -->
        <result column="source_name" property="sourceName"/>
        <result column="created" property="created"/>
        <result column="updated" property="updated"/>
        <result column="status" property="status"/>
    </resultMap>

修改sql配置,不能在配置resultType了,要配置resultMap。(这两个属性是互斥的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AT9DxVlP-1671874123597)(笔记.assets/1665197228041.png)]

测试!

映射文件的配置

sql片段

我们可以在映射文件中设置一个sql片段,在其他的sql语句中引用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUdD7tKq-1671874123597)(笔记.assets/1665198525987.png)]

select语句的属性配置

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetTypeFORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
resultOrdered这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false
resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。
  • parameterType 配置参数类型,参数类型可以是简单类型(基本类型和String),也可以是集合类型,也可以是实体类类型。

在MyBatis中内置了一部分类型,而且每个类型都有对应的别名:

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator
  • resultType预期的返回值类型

可以是任何内置的类型或者我们自定义的pojo。如果返回的是list,一定要配置list的泛型类型。

resultType和resultMap是互斥的属性,不能同时配置。

  • resultMap 配置结果映射

大部分情况下我们都会有结果映射配置。在前面的案例中我们用resultMap解决了列名和属性名不一致的情况。

insert, update 和 delete配置

insert、update和delete是没有resultType或者resultMap的配置的,默认返回值类型都是int类型的。

可以配置parameterType。也没有缓存相关的配置,只有刷新缓存的配置。

在insert语句中有个特殊的配置。

属性描述
useGeneratedKeys(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

之前遇到问题:当一个数据表的主键是自增列的时候,我们添加一条数据进去之后希望可以得到刚刚生成的id。这时我们的做法是在同一个事务中立刻查询。

MyBatis可以通过上面的设置解决这个问题。

当我们配置了useGeneratedKeys为true的时候,MyBatis会将自增列的结果直接回填到对象中。

案例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUIrjENB-1671874123597)(笔记.assets/1665199381763.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yN1grYtj-1671874123598)(笔记.assets/1665199495467.png)]

除过上面的解决方案之外,还有一个解决方案。

问题:有的时候,我们的主键不是自增列,也不是手动设置的而是从其他数据表获取的。MyBatis就提供了解决方案。(我们这里还是使用自增列演示)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3knfDbIu-1671874123598)(笔记.assets/1665199754505.png)]

sql语句的参数设置

[1]关于#和$

#{xxx} 如果只有一个参数,xxx可以随意。

看问题:通过名称模糊查询用户

sql:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VIVmUC14-1671874123598)(笔记.assets/1665199981228.png)]

不用测试:这个sql肯定不行,因为MyBatis会将#{username} 直接作为字符串处理。

解决方案1:

修改sql:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYA0YbIe-1671874123599)(笔记.assets/1665200144386.png)]

测试程序:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lmp2qW48-1671874123599)(笔记.assets/1665200164685.png)]

解决方案2:我们可以使用${}

修改sql:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s7bYj3sh-1671874123600)(笔记.assets/1665200220400.png)]

tips: 当使用${}接收参数的时候,如果参数只有一个简单类型的值,则这里引用的参数的名字必须是固定字符串value 如果是pojo或者map 则要写对应的key或者属性名。

测试程序:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RR2L9p3X-1671874123600)(笔记.assets/1665200291520.png)]

# 使用使用占位符的方式设置sql中的参数的。

$ 是使用字符串连接的方式将参数设置到sql中的。

[2]简单类型

我们这里说的简单类型是只基本类型和String

简单类型如果是单个参数 #{随意} ${value } 直接可以接收。

[3] pojo类型

添加和修改操作往往传递的参数都是pojo类型。这时在sql中获取数据的时候要注意:

#{对象的属性名} 同理 ${对象的属性名}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMHXJZ6S-1671874123600)(笔记.assets/1665200658022.png)]

[4] 参数是map类型的

如果参数类型是map类型,我们可以使用#{key}获取对应的值。

我们实现添加source的方法:使用map作为参数。

在SourceMapping.xml 中添加sql:

<!-- 添加source,使用map作为参数 -->
<insert id="saveSource" parameterType="map">
    insert into source(source_name,created,updated,status)
    values (#{sName},#{created},#{updated},#{status})
</insert>

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xbvwfZX-1671874123600)(笔记.assets/1665200982441.png)]

返回值类型

[1]一行一列的简单类型

查询总条数

sql语句:

    <!-- 查询总条数 -->
    <select id="count" resultType="int">
        select count(*) from user
    </select>

测试程序:

@Test
public void testCount(){
    // 获取一个SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    Integer o = sqlSession.selectOne("com.qidian.UserMapping.count");
    System.out.println(o);
}

[2]返回一个pojo对象

    <!-- 这里是查询的sql语句的配置 -->
    <select id="selectUser" resultType="com.qidian.pojo.User">
        select * from user where id = #{id}
    </select>

[3]返回一个列表

tips:resultType要写list中的泛型类型

<!-- 通过名称模糊查询用户 -->
<select id="selectUserByUsername" resultType="com.qidian.pojo.User">
    select * from user where username like #{username}
</select>

[4]返回一个map

需求:查询一个source,返回类型为map

sql:

<select id="queryByIdForMap" parameterType="long" resultType="map">
    select * from source where id = #{id}
</select>

测试程序:

    @Test
    public void testSelectForMap(){
        // 获取一个SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Map map = sqlSession.selectOne("com.qidian.SourceMapping.queryByIdForMap", 2L);
        System.out.println(map);
    }

[5]返回值类型是list,其中的泛型是map

查询所有的source,

<select id="selectAllForMap" resultType="map">
    select * from source
</select>

测试程序:

@Test
public void testSelectAllForMap(){
    // 获取一个SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    List<Map> map = sqlSession.selectList("com.qidian.SourceMapping.selectAllForMap");
    System.out.println(map);
}

DAO的开发:传统方式

有如下的接口:

/**
 * @author 戴着假发的程序员
 * @company 起点编程
 * 2022/10/8 14:36
 */
public interface SourceDAO {
    int save(Source source);
    List<Source> queryAll();
    Source queryById(Long id);
}

实现类:

我们可以将获取sqlSessionFactory的过程设置为公共的。不需要每次都获取。

/**
 * @author 戴着假发的程序员
 * @company 起点编程
 * 2022/10/8 14:39
 */
public class SourceDAOImpl implements SourceDAO {
    // 这一部分的内容可以写在BaseDAO中的
    private static SqlSessionFactory sqlSessionFactory = null;
    static{
        // 主配置文件的位置
        String resource = "mybatis-config.xml";
        // 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            // 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //-----------------------------

    public int save(Source source) {
        int result = -1;
        SqlSession sqlSession = sqlSessionFactory.openSession();
        result = sqlSession.insert("com.qidian.SourceMapping.save",source);
        sqlSession.commit();
        return result;
    }

    @Override
    public List<Source> queryAll() {
        return sqlSessionFactory.openSession().selectList("com.qidian.SourceMapping.selectAll");
    }

    @Override
    public Source queryById(Long id) {
        return (Source) sqlSessionFactory.openSession().selectOne("com.qidian.SourceMapping.selectById",id);
    }
}

对应的mapper文件中的sql语句:

<!-- 添加source,使用map作为参数 -->
<insert id="save" parameterType="map">
    insert into source(source_name,created,updated,status)
    values (#{sourceName},#{created},#{updated},#{status})
</insert>
    <select id="selectById" parameterType="long" resultType="com.qidian.pojo.Source">
        select * from source where id = #{id}
    </select>
    <select id="selectAll" resultMap="baseResultMap">
        select <include refid="allColumns"/> from source
    </select>

DAO开发:代理mapper方式

要开发的接口:

tips这里的接口是mapper不再是DAO了。

/**
 * @author 戴着假发的程序员
 * @company 起点编程
 * 2022/10/8 14:49
 */
public interface UserMapper {
    int save(User user);
    User queryById(Long id);
    List<User> queryByName(String name);
    List<User> queryAll();
    int count();
}

在resources/maps下添加一个配置文件: UserMapper.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQ9h6XLK-1671874123601)(笔记.assets/1665211991819.png)]

tips:mapper文件中的namespace必须写UserMapper接口的全限定类名。

在mapper中添加sql语句,添加的要求

①UserMapper接口中的每一个方法都必须对应的写一条sql语句。

②Sql语句的id必须和UserMapper接口中对应的方法的名字一致。

<?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 相当于当前文件的唯一标志 -->
<!-- 这里的namespace必须写对应的接口的全限定类名 -->
<mapper namespace="com.qidian.dao.UserMapper">
    <!-- 这里的id必须和方法名对应 -->
    <insert id="save" parameterType="com.qidian.pojo.User">
        insert into user(username,usertel,userage)
        values(#{username},#{usertel},#{userage})
    </insert>
    
    <!-- 根据id查询 -->
    <select id="queryById" parameterType="long" resultType="com.qidian.pojo.User">
        select * from user where id = #{id}
    </select>
    <!-- 根据名称模糊查询 -->
    <select id="queryByName" parameterType="string" resultType="com.qidian.pojo.User">
        select * from user where username like '%${value}%'
    </select>
    <!-- 查询全部 -->
    <select id="queryAll" resultType="com.qidian.pojo.User">
        select * from user
    </select>
    <!-- 查询总条数 -->
    <select id="count" resultType="int">
        select count(*) from user
    </select>
</mapper>

【1】接口中的每一个方法都必须在mapper文件中有对应的sql。

【2】mapper文件中的sql语句可以多。

【3】接口中不能有重载的方法。

我们使用代理mapper实现CRUD。(我们不写实现类)

测试:

/**
 * @author 戴着假发的程序员
 * @company 起点编程
 * 2022/10/8 15:00
 */
public class ProxyMapperTest {
    private SqlSessionFactory sqlSessionFactory = null;
    @Before // 在单元测试之前执行
    public void before() throws IOException {
        // 主配置文件的位置
        String resource = "mybatis-config.xml";
        // 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testSave(){
        User user = new User();
        user.setUsertel("15815815826");
        user.setUserage(18);
        user.setUsername("如花");
        // 调用Mapper进行保存
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        int save = userMapper.save(user);
        sqlSession.commit();
        System.out.println(save);
    }

    @Test
    public void testQuery(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 获取一个动态代理产生的mapper对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 调用方法
        System.out.println(userMapper.count());
        System.out.println(userMapper.queryById(1L));
        System.out.println(userMapper.queryAll());
        System.out.println(userMapper.queryByName("卡"));
    }
}

@Test
public void testSave(){
User user = new User();
user.setUsertel(“15815815826”);
user.setUserage(18);
user.setUsername(“如花”);
// 调用Mapper进行保存
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int save = userMapper.save(user);
sqlSession.commit();
System.out.println(save);
}

@Test
public void testQuery(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取一个动态代理产生的mapper对象
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 调用方法
    System.out.println(userMapper.count());
    System.out.println(userMapper.queryById(1L));
    System.out.println(userMapper.queryAll());
    System.out.println(userMapper.queryByName("卡"));
}

}

作品转自@戴着假发的程序员
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值