首页 > 其他分享 >03_MyBatis02

03_MyBatis02

时间:2023-07-04 10:44:13浏览次数:45  
标签:03 UserMapper public sqlSession user MyBatis02 id User

1. 深入Mybatis映射配置文件

1.1. CRUD语句定义

查询语句

UserMapper.java接口中

public List<User> queryAllUser();

public User queryUserById(Integer id);

UserMapper.xml配置文件中

<select id="queryAllUser" resultType="uSer">
	select * from user;
</select>

<!--根据id查询用户信息-->
<!--#{} : 如果传递的参数是基本数据类型,其中的内容可以随便写
            如果传递的参数是实体类对象类型,其中的内容必须是实体类属性名
            parameterType:Mybatis允许不写,会自动进行类型转换,
            如果参数需要数值类型,传递的是字符串:
            1.如果字符串是纯数字,直接转换
            2.如果字符串是数字+字符形式,会将数字之后的字符提
            出,只留数字转换
            3.如果字符串是字符+数字形式,无法转换
-->
<select id="queryUserById" parameterType="int" resultType="user">
	select * from user where id=#{传递的参数是id}
</select>

MybatisTest.java单元测试类

@Test
public void test1(){
    SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.queryAllUser();
    System.out.println(users);
}

@Test
public void test2(){
    SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);
}

插入语句

普通插入语句

UserMapper.java接口中

public void insertUser(User user);

UserMapper.xml配置文件中

<insert id="insertUser" parameterType="user">
	insert into user(id,user_name,password) values(#{id},#{userName},#{password})
</insert>

MybatisTest.java单元测试类

@Test
public void test3(){
    SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User(7,"张飞","23423");
    mapper.insertUser(user);
    //sqlSession.commit();
}

细节

mybatis默认会开启事务执行操作,但是默认是不会自动提交事务,所以插入操作执行之后,需要手动提交事务,或者配置sqlSession自动提交事务。

如何返回数据库自增的ID

如何返回数据库自增的ID Mybatis默认插入数据之后,是不会返回新插入数据的id的。

UserMapper.java接口中

public void insertUserGetId(User user);

UserMapper.xml配置文件中

<insert id="insertUserGetId" parameterType="user">
	insert into user(user_name,password) values(#{userName},#{password})
</insert>

MybatisTest.java单元测试类

@Test
public void test4(){
    SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    user.setUserName("关平");
    user.setPassword("234234");
    mapper.insertUserGetId(user);
    System.out.println(user.getId());
}

运行测试,会发现并不能在插入操作之后,获取新插入数据的id.
image

如果想要在插入数据之后立刻返回新插入数据的id,需要进行以下操作。

方式一:

<!--添加用户,获取新增用户的自增id方式一
        useGeneratedKeys : true表示可以获取新增数据主键
        keyColumn : 数据库表中主键字段的名称
        keyProperty : 参数条件实体类对象的属性名,表示存放数据库主键字段数据的属性
-->
<insert id="insertUserGetId" parameterType="user" useGeneratedKeys="true"
keyColumn="id" keyProperty="id">
	insert into user(user_name,password) values(#{userName},#{password})
</insert>

方式二:

<!--添加用户,获取新增用户的自增id方式二
		selectKey : 存放获取新增数据主键数据的sql语句
		order: 在新增之前还是之后执行sql语句 BEFORE:之前 AFTER:之后
        keyColumn : 数据库表中主键字段的名称
        keyProperty : 参数条件实体类对象的属性名,表示存放数据库主键字段数据的属性
		resultType : 查询的主键字段的类型
-->
<insert id="insertUserGetId" parameterType="user">
	<selectKey keyColumn="id" keyProperty="id" resultType="integer" order="AFTER">
		select LAST_INSERT_ID();
	</selectKey>
	insert into user(user_name,password) values(#{userName},#{password})
</insert>

会发现可以获取到新插入的数据的id。

image

删除语句

UserMapper.java接口中

public void deleteUserById(Integer id);

UserMapper.xml配置文件中

<delete id="deleteUserById" parameterType="integer">
	delete from user where id=#{id}
</delete>

MybatisTest.java单元测试类

@Test
public void test5(){
    SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.deleteUserById(16);
}

更新语句

UserMapper.java接口中

public void updateUser(User user);

UserMapper.xml配置文件中

<update id="updateUser" parameterType="user">
	update user set password=#{password} where id=#{id}
</update>

MybatisTest.java单元测试类

@Test
public void test6(){
    SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    user.setId(15);
    user.setPassword("spring");
    mapper.updateUser(user);
}

1.2. 接口中的参数如何传递到SQL中

简单类型参数

UserMapper.java接口中:

public void deleteUserById(Integer id);

UserMapper.xml配置文件中:

<delete id="deleteUserById" parameterType="integer">
	delete from user where id=#{id}
</delete>

引用类型参数

UserMapper.java接口中:

public void insertUser(User user);

UserMapper.xml配置文件中:

<insert id="insertUserGetId" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
	insert into user(user_name,password) values(#{userName},#{password})
</insert>

多参数传递

方式一

如果传递的参数有多个,Mybatis默认会按照传递参数的顺序命名为arg0、arg1......,在映射文 件中可以直接使用arg0、arg1......获取传递的参数。

UserMapper.java接口中

public User queryUserByIdAndUserName(int id,String userName);

UserMapper.xml配置文件中

<!--多参数传递方式一
        arg0和arg1固定写法
        arg0表示mapper接口方法第一个参数
        arg1表示mapper接口方法第二个参数
-->
<select id="queryUserByIdAndUserName" resultType="user">
	select * from user where id=#{arg0} and user_name=#{arg1}
</select>

方式二

如果传递的参数有多个,Mybatis默认会按照传递参数的顺序命名为param1、param2......,在 映射文件中可以直接使用param1、param2......获取传递的参数。

UserMapper.java接口中

public User queryUserByIdAndUserName(int id,String userName);

UserMapper.xml配置文件中

<!--多参数传递方式二
        param1和param2固定写法
        param1表示mapper接口方法第一个参数
        param2表示mapper接口方法第二个参数
-->
<select id="queryUserByIdAndUserName" resultType="user">
	select * from user where id=#{param1} and user_name=#{param2}
</select>

方式三

如果传递的参数有多个或接口方法中的参数名称和映射文件中使用的参数名称不一致,可以使用 @param()指定接口方法参数在映射文件中使用的名称。

UserMapper.java接口中

//@Param : 给mapper接口方法的参数设置一个在mapper.xml文件中使用的名称
public User queryUserByIdAndUserName(@Param("id") int id,
@Param("userName") String userName);

UserMapper.xml配置文件中

<!--多参数传递方式三-->
<select id="queryUserByIdAndUserName" resultType="user">
	select * from user where id=#{id} and user_name=#{userName}
</select>	

MybatisTest.java单元测试类

@Test
public void queryUserByUserNameAndPassWordTest() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("Mybatis-Config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);//采用动态代理的方式,构建出usermapper实现类对象
    
    User user = mapper.queryUserByIdAndUserName(10, "赵云");
    System.out.println(user);
    
    sqlSession.close();
}

#{}与${}的区别

共同点:

​ 它俩都可以获取接口调用中传递过来的参数。

区别:

#{} (建议使用)

​ 1.表示占位符 ?

​ 2.如果参数只有一个基本类型,#{名称}中的名称可以随便写

​ 3.如果参数是实体类对象类型,#{名称}必须实体类中的属性名一致

​ 4.可以防止sql语句注入

${}

​ 1.直接拼接sql, '${username}'

​ 2.如果参数只有一个基本类型参数低版本必须使用${value},但是高版本可以随便写

​ 3.如果参数是实体类对象类型,${名称}必须实体类中的属性名一致

​ 4.不可以防止sql注入,比如:内容为' or '1'='1

比如,要实现下面的效果:

UserMapper.java接口中

public User selectUserById(int id); //ctrl+d复制一行 ctrl+y删除一行
public User selectUserByUserName(String userName); //ctrl+d复制一行ctrl+y删除一行
public List<User> selectUserByStrId(String id);

UserMapper.xml配置文件中

<!--${}用法-->
<select id="selectUserById" parameterType="_int" resultType="user">
	select * from user where id=${随便写}
</select>
<select id="selectUserByUserName" parameterType="string" resultType="user">
	select * from user where user_name='${随便写}'
</select>
<select id="selectUserByStrId" parameterType="string" resultType="user">
	select * from user where id='${id}'
</select>

MybatisTest.java

@Test
public void selectUserByIdTest() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("Mybatis-Config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);//采用动态代理的方式,构建出usermapper实现类对象
    
    User user = mapper.selectUserById(10);
    System.out.println(user);
    
    sqlSession.close();
}

@Test
public void selectUserByUserNameTest() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("Mybatis-Config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);//采用动态代理的方式,构建出usermapper实现类对象
    
    User user = mapper.selectUserByUserName("赵云");
    System.out.println(user);
    
    sqlSession.close();
}

@Test
public void selectUserByStrIdTest() throws IOException {
    InputStream resourceAsStream =Resources.getResourceAsStream("Mybatis-Config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);//采用动态代理的方式,构建出usermapper实现类对象
    
    List<User> user = mapper.selectUserByStrId("' or '1'='1");
    System.out.println(user);
    
    sqlSession.close();
}

细节:

如果使用#{id}取获取参数,最终执行的SQL会是这样:

image

如果使用${id}来取参数,最终执行的SQL会是这样:

image

1.3. 结果集如何映射

ResultType方式

ResultType方式适用于数据库结果集可以直接映射成一个Java类的情况

Java实体类:

public class User {

    private int id;
    private String userName; //可以通过Mybatis的配置实现 user_name和userName的对应
    private String password;
    
    public User() {
    }
    
    public User(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }
    
    public User(int id, String userName, String password) {
        this.id = id;
        this.userName = userName;
        this.password = password;
    }
    
    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 getPassword() {
    	return password;
    }
    
    public void setPassword(String password) {
    	this.password = password;
    }
    
    @Override
    public String toString() {
        return "User{" +
        "id=" + id +
        ", userName='" + userName + '\'' +
        ", password='" + password + '\'' +
        '}';
    }
}

使用方法:

<select id="queryAllUser" resultType="uSer">
	select * from user;
</select>

ResultMap方式

ResultMap方式适用于复杂的结果集映射,比如数据库返回的结果集中的列名和JavaBean无法一 一对应,或者对象间存在一对一、一对多关联映射时。

解决数据库列名与Java类中属性名不一致的映射问题

User_ResultMap.java实体类

public class User_ResultMap {

    private Integer id;
    private String un;
    private String pw;
    
    public User_ResultMap() {
    }
    
    public User_ResultMap(String un, String pw) {
        this.un = un;
        this.pw = pw;
    }
    
    public User_ResultMap(Integer id, String un, String pw) {
        this.id = id;
        this.un = un;
        this.pw = pw;
    }
    
    public Integer getId() {
    	return id;
    }
    
    public void setId(Integer id) {
    	this.id = id;
    }
    
    public String getUn() {
    	return un;
    }
    
    public void setUn(String un) {
    	this.un = un;
    }
    
    public String getPw() {
    	return pw;
    }
    
    public void setPw(String pw) {
    	this.pw = pw;
    }
    
    @Override
    public String toString() {
        return "User_ResultMap{" +
            "id=" + id +
            ", un='" + un + '\'' +
            ", pw='" + pw + '\'' +
            '}';
        }
}

UserResultMapMapper.java接口

public interface UserResultMapMapper {
	public List<User_ResultMap> queryAllUser();
}

UserResultMapMapper.xml配置文件

<mapper namespace="com.test.mybatis.mapper.UserResultMapMapper">
    <select id="queryAllUser" resultType="User_ResultMap">
    	select * from user;
    </select>
</mapper>

MybatisResultMapTest.java单元测试

public class MybatisResultMapTest {
    @Test
    public void test1(){
        SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserResultMapMapper mapper = sqlSession.getMapper(UserResultMapMapper.class);
        List<User_ResultMap> user_resultMaps = mapper.queryAllUser();
        System.out.println(user_resultMaps);
	}
}

单元测试执行之后,会发现数据库返回的结果集中和JavaBean属性名称不一致的数据是无法映射 存储到JavaBean中的。

image

这是就需要使用ResultMap进行手动映射处理。

<!--id:resultmap的唯一标识
	type:resultmap的类型,即数据库查询数据封装到哪个实体类对象中
-->
<resultMap id="userResultMap" type="user_ResultMap">
    <!--主键关系映射对应 column:数据库查询出来的主键字段的名称 property:实体
    类中和数据库查询出来的主键对应的属性的名称-->
    <id column="id" property="id"></id>
    <!--其他字段关系映射对应-->
    <result column="user_name" property="un"></result>
    <result column="password" property="pw"></result>
</resultMap>

在查询语句中将resultType换成resultMap

<select id="queryAllUser" resultMap="userResultMap">
	select * from user;
</select>

image

如果遇到单纯字段名和属性名不对应的情况,使用别名的方式更简单

<!--明知道数据库表查询字段和实体类属性名称不对应,但是就是使用resulttype去封装处
理数据,怎么保证数据全部查询封装起来-->
<select id="queryAll" resultType="user_ResultMap">
	select id,user_name un,password pw from user
</select>

2. PageHelper分页的插件

概述

PageHelper非Mybatis官方提供,是开源社区的开发者自己编写的一个用于完成分页查询的 Mybatis插件,开源在Github中。

使用方法

  1. 添加依赖
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>
  1. 在Mybatis核心配置文件中配置插件

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 如果当前页超出合法范围,是否返回正确结果 -->
            <property name="reasonable" value="true"/>
            <!-- 如果每页显示条数传入0,是否返回所有数据(不分页) -->
            <property name="pageSizeZero" value="true"/>
        </plugin>
    </plugins>
    
  2. PageHelperMapper.java接口中

    public interface PageHelperMapper {
    	public List<User> pageQueryUser();
    }
    
  3. PageHelperMapper.xml配置文件中

    <select id="pageQueryUser" resultType="user">
    	select * from user
    </select>
    
  4. 调用分页方法

    public class PageHelperTest {
        @Test
        public void test1(){
            SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
            SqlSession sqlSession = sqlSessionFactory.openSession();
            PageHelperMapper mapper =sqlSession.getMapper(PageHelperMapper.class);
            PageHelper.startPage(2,3);
            Page<User> page= (Page<User>) mapper.pageQueryUser();
            System.out.println(page);
        }
    }
    

image

​ 会发现使用PageHelper进行分页查询时,获取的数据被封装到Page中。

获取分页参数

在调用了分页方法之后再执行查询操作,返回结果的实际类型其实是 com.github.pagehelper.Page 类型,由于该类型继承了ArrayList,所以我们可以使用List接收。

Page类型封装了分页插件给我们计算好的所有分页参数

Page{count=true, pageNum=703, pageSize=100, startRow=70200, endRow=70300,
total=70238, pages=703, reasonable=true, pageSizeZero=true}

比如我们像下面这样获取总记录数和总页数

public class PageHelperTest {
    @Test
    public void test1(){
        SqlSessionFactory sqlSessionFactory = MybatisUtil.getSqlSessionFactory("Map-Config.xml");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        PageHelperMapper mapper =sqlSession.getMapper(PageHelperMapper.class);
        //方式一
        //PageHelper.startPage(2,3);
        //Page<User> page= (Page<User>) mapper.pageQueryUser();
        
        //方式二
        Page<User> page = PageHelper.startPage(2, 3).doSelectPage(new ISelect() {
            @Override
            public void doSelect() {
                mapper.pageQueryUser();
            }
        });
        
        //获取总条数
        long total = page.getTotal();
        //获取总页数
        int pages = page.getPages();
        //获取每页显示条数
        int pageSize = page.getPageSize();
        //获取当前页
        int pageNum = page.getPageNum();
        //获取查询结果
        List<User> user = page.getResult();
        
        System.out.println(user);
        
        System.out.println(total+":"+pages+":"+pageSize+":"+pageNum);
    }
}

分页插件配置项(可选)

分页插件所有参数都是可选的,我们一般不配置参数。

下面列举了一些可能会用到的参数:

  • pageSizeZero :默认值为 false ,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果 仍然是 Page 类型)。
  • reasonable :分页合理化参数,默认值为 false 。当该参数设置为 true 时, pageNum<=0 时会查询第一页, pageNum>pages (超过总数时),会查询最后一页。默认 false 时,直接根据参数进行查询。

要查看所有支持的参数参见:https业github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

标签:03,UserMapper,public,sqlSession,user,MyBatis02,id,User
From: https://www.cnblogs.com/jiabaolatiao/p/17525057.html

相关文章

  • SSO2.0 19-20230703
         ......
  • Variable 'xxxx' is accessed from within inner class, needs to be final or effect
    问题的原因问题代码:publicstaticvoidmain(String[]args){Integersum=0;Integercount=0;List<Integer>list=newArrayList<>(Arrays.asList(1,2,3,4,5));list.stream().forEach(e->{sum+=e;//这步会编译错误--Varia......
  • requests.exceptions.ProxyError: HTTPSConnectionPool(host='xxx', port=443)
    #绕过系统设置的代理#方法一:session=requests.Session()session.trust_env=Falseresponse=session.get('http://ff2.pw')#方法二:(多人亲测可以直接结局这个问题)proxies={"http":None,"https":None}requests.get("http://ff2.pw",proxi......
  • 503. 下一个更大元素 II
    labuladong题解难度中等824给定一个循环数组 nums ( nums[nums.length-1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的......
  • 7/03
    今天又是阴天下雨,从早上开始,就一直哗啦啦的下,雨水冲刷过后空气变得十分清凉,我一个人在家感到一丝无聊。我像平时一样八点多起来,学了一会黑马程序,然后我妈给我打电话了,告诉我我弟有一份期末资料没有打印,要我打印后给弟弟送去,我骑电车去打印。外面雨停了,很凉快,不知道弟弟有没有好好......
  • 2023-07-03:讲一讲Redis缓存的数据一致性问题和处理方案。
    2023-07-03:讲一讲Redis缓存的数据一致性问题和处理方案。答案2023-07-03:数据一致性当使用缓存时,无论是在本地内存中缓存还是使用Redis等外部缓存系统,会引入数据同步的问题。下面以Tomcat向MySQL中进行数据的插入、更新和删除操作为例,来说明具体的过程。分析下面几种解......
  • [LOJ 6030]「雅礼集训 2017 Day1」矩阵 题解
    首先不难想到一个贪心,就是先填出一个全黑的行,然后再用其填黑列。而且在其中“填出一个全黑的行步数”我们应该最小化。这个贪心的正确性证明如下:必要性:填黑列的必要条件为有一个全黑的行。充分性:“填黑列的步数”就是“非全黑列的数量”。显然,如果填出一个全黑的行的过程中......
  • 20230703测试
    A我不打了,但是考场上没想起来排列stl怎么写,所以在下面打10遍next_permutationnext_permutationnext_permutationnext_permutationnext_permutationnext_permutationnext_permutationnext_permutationnext_permutationnext_permutationnext_permutation你可以数......
  • 2023/7/03
    今天学习了Java中的inal,多态抽象类和接口final相当于C++中的const,对于用final声明的变量,一旦被设定,就不能改变改变量的值,一对象的引用被final修饰后,他就只能恒定指向一个对象无法使其指向另一个对象。在父类中被final修饰的方法不能在子类中被隐藏,被final修饰的类是不能被继承的......
  • 20230703赛后复盘
    复盘时间安排8:00~8:30写&调试T1正解,过样例8:30~8:50想写T2正解,然而胡错了(所以又重写了)8:50~9:10写T2的\(O(kn^2)\)部分分然后瞟了眼T3感觉不会,跳过去看T49:10~9:40推T4的正解。推了一半,卡在进位的处理上(悲)9:40~9:50爬去写暴力9:50~10:00回头写了个T3部分分最后一个多......