MyBatis入门
MyBits快速实现
首先在pom文件中照着官文配置
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version> </dependency>
型号自己选
其余常用的依靠后期写在一个xml文件里下次要用直接复制
<!-- junit 单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.2</version> <scope>test</scope> </dependency> <!-- 添加slf4j日志api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> </dependency> <!-- 添加logback-classic依赖 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- 添加logback-core依赖 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies>
随后在资源目录下创建一个mybtis核心配置文件同样使用官文的模板
具体信息根据版本以及需要更改,有时候报错要么是jdk版本太高,要么是写的url不符合现在jdbc的版本
<?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/sql_store?characterEncoding=utf-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="20001103"/> </dataSource> </environment> </environments> <mappers> <!-- 加载sql的映射文件--> <mapper resource="UserMapper.xml"/> </mappers> </configuration>
这里的添加映射文件,是手动单个单个添加的,后面多了直接放到resources的一个目录里,(注意用com/xxx/xxx来创建目录,目录名称和上面写的接口所在路径名称最好一样)
U
你会发现最后还要加载sql映射文件,这是用来储存SQL语句的所以我们在resources下再创建一个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:名称空间--> <mapper namespace="text"> <select id="selectAll" resultType="com.itheima.pojo.User"> select * from tb_user; </select> </mapper>
随后是写一个类来接收数据,类的变量要和返回的数据一一对应
再alt+insert写出所有变量的getset方法,以及重写toString
最后就是写一个主类来加载核心文件,接收输出数据,在官文上也是有具体模板的,只是自己要实现的功能要自己添加
package com.itheima; import com.itheima.pojo.User; 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 java.io.IOException; import java.io.InputStream; import java.util.List; /*Mybits快速入门代码*/ public class MybatisDemo { public static void main(String[] args) { // 加载mybits的核心配置文件,获取SqlSessionFactoory String resource = "mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取SqlSession对象,用它执行sql SqlSession sqlSession=sqlSessionFactory.openSession(); // 执行sql List<User> users=sqlSession.selectList("text.selectAll"); //这里的text是对应xml文件中的名称空间后面跟上其id System.out.println(users); // 释放资源 sqlSession.close(); } }
我们只需要处理异常增加具体功能就好了如上
(说一下,今天遇到了两个问题,一个是自己的maven仓库,这是因为idea不支持太新的maven包,我去官网下载了3.8之前的版本就好了。第二个是jdk语言版本太高了,mybtis也不支持,在pom文件里加上解决了语言,还有就是url中不支持&需要用
&
代替)
运行完之后返现有个sql语句警告
产生的原因是idea和数据库没有建立连接,不识别表信息,我们只用在idea中配置Mysql数据库连接就可以解决了
Mapper代理开发
在MyBits基础开发里我们主类通过传入sql映射空间里的名称空间.sql语句id的方式传入sql语句并执行
这种方式后期企业中sql语句多了,对应的id多了,写起来还是不太方便,这里在官网其实也提到过
这其实就是建议我们可以用代理开发
下面三点是使用mapper需要遵守的规则三点
这里我们第一步定义接口同名
然后我们更改名称空间
然后我们去看xml文件中
所以我们在接口中完成如下
public interface UserMapper { List<User> selectAll(); }
这里用集合user而不是user对象因为我们是查询所有,返回的是集合,如果是单个当然只用user就可以了(具体视情况变动)
编写映射文件的注意事项:
- XML文件名的命名必须和Mapper接口名称相同。
- SQL映射文件中命名空间namespace必须对应Mapper接口的全限定类名。
- 增删改查元素中的id与Mapper接口中的方法必须对应。
- parameterType的类型必须和Mapper接口方法的输入参数类型相同(有时可以省略)。
- resultType的类型必须和Mapper接口方法的输出参数类型相同。
最后完成我们的主类,我们用mapper代理的方式替换刚刚的语句
SqlSession sqlSession=sqlSessionFactory.openSession(); // 执行sql // List<User> users=sqlSession.selectList("text.selectAll"); // 3.1获取UserMapper接口的代理对象 UserMapper userMapper=sqlSession.getMapper(UserMapper.class); List<User> users=userMapper.selectAll();
用了mapper方式我们也可以简化我们的加载sql映射的语句
原本我们如果有多个sql映射的文件都要导入我们就要写多条
类似的语句,那么我们可以直接用包扫描的形式加载包下所有的映射
这里要使用扫描包的方式导入需要注意的是在resources包下创建目录的时候要用com/itheima/mappers,而不能用.,否者是不能扫包的
Mybits核心配置文件
具体的可以去仔细看官文
别名的配置(要写到environments前面):
配置是需要遵守官方的顺序的
练习1,查询所有数据test
目标及步骤如下
一共需要三步来完成mybits的增删改查
1.编写接口方法
2.编写Sql语句
你发现爆红,你alt+ent就可以直接写好框架
随后你完成sql语句的书写
3.执行方法
在测试类中完成
public class MyBatisTest { @Test public void testSelectAll(){ // 1.获取SqlSessionFactory(直接官文复制或者原来的工程中复制) String resource = "mappers/mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取SqlSession对象 SqlSession sqlSession= sqlSessionFactory.openSession(); // 3.获取Mapper接口的代理对象 BrandMapper brandMapper= sqlSession.getMapper(BrandMapper.class); // 执行方法 List<Brand> brands=brandMapper.selectAll(); System.out.println(brands); // 释放资源 sqlSession.close(); } }
这里要注意,如果你在mybatis-config文件中不是用的扫包的方式,那么你需要到里面去为工程手动加载SQL映射文件
这里查询过后我们发现有些结果没有被封装到
这是因为sql语句中的命名和java中的命名不能一一对应上,使得数据识别不出
<!--数据库表的字段名称和实体类的属性名称不一样,则不能自动封装数据 解决方法: 1.起别名(每次查询都要定义别名,不方便) 2.resultMap:id标签-完成主键字段的映射的 result完成一般字段的映射 先写一个resultMap组件,type为要映射的对象,这里使用了别名brand(返回数据要封装的对象对应了类Brand) column是sql语句中列的名字,property是类中与之对应的名字 再到sql中将resultType改成resultMap并且导入对应的resultMap id --> <resultMap id="brandResultMap" type="brand"> <result column="brand_name" property="brandName"/> <result column="company_name" property="companyName"/> </resultMap> <select id="selectAll" resultMap="brandResultMap"> SELECT * FROM tb_brand; </select> <!-- <select id="selectAll" resultType="brand">--> <!-- SELECT id, brand_name AS brandName, company_name AS companyName, ordered, description, status--> <!-- FROM tb_brand;--> <!-- </select>-->
练习2,根据传入id查询数据
接口中定义方法
<!-- mybatis参数占位符: 1.#{}:会将其替换为?,为了防止sql注入 2.${}:直接完成sql语句的拼接,会纯在sql注入的问题 3.使用时机 *参数传递的时候用#{} *表名或者列名不固定的情况下:${} 会存在sql注入的问题 参数类型 select框架里属性parameterType定义参数类型(可以省略) 特殊字符的处理 <号无法使用就要用转义字符< 或者CDATA区; --> <!-- <select id="selectById" parameterType="int" resultMap="brandResultMap">--> <!-- SELECT *--> <!-- FROM tb_brand WHERE id=#{id};--> <!-- </select>--> <select id="selectById" parameterType="int" resultMap="brandResultMap"> SELECT * FROM tb_brand WHERE id <![CDATA[ < ]]> #{id}; </select>
sql映射文件中写好方法
mybatis参数占位符:
1.#{}:会将其替换为?,为了防止sql注入
2.${}:直接完成sql语句的拼接,会纯在sql注入的问题
3.使用时机
*参数传递的时候用#{}
*表名或者列名不固定的情况下:${} 会存在sql注入的问题
参数类型 select框架里属性parameterType定义参数类型(可以省略)
特殊字符的处理 <号无法使用就要用转义字符< 或者CDATA区在需要写特殊字符的地方输入CD会有提示回车后在里面写上要用的字符;
在测试类中完成测试方法,调用所需方法传入参数
@Test public void testSelectById(){ // 接收参数 int id=1; // 1.获取SqlSessionFactory(直接官文复制或者原来的工程中复制) String resource = "com/itheima/mappers/mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取SqlSession对象 SqlSession sqlSession= sqlSessionFactory.openSession(); // 3.获取Mapper接口的代理对象 BrandMapper brandMapper= sqlSession.getMapper(BrandMapper.class); // 执行方法 Brand brand=brandMapper.selectById(id); System.out.println(brand); // 释放资源 sqlSession.close(); }
练习3,多条件查询
主要是练习三种不同的多参数接收方式
目标用户通过输入三个条件搜索符合条件的数据
这就使得我们的sql语句必须是动态的(占位符),且会含有多个参数。
所以我们可以先写sql语句
<!--条件查询--> <select id="selectByCondition" resultMap="brandResultMap"> SELECT* FROM tb_brand WHERE status=#{status} AND company_name LIKE #{companyName} AND brand_name LIKE #{brandName} </select>
再去接口中完成对应的方法
多个参数接收处理的三种方式
条件查询
多个参数接收
1.散装参数 通过@Param("SQL参数占位符名称")
2.对象参数 对象的属性名称要和参数占位符名称一致
3.map处里参数 通过map键值对处理参数
1.散装
List<Brand> selectByCondition(@Param("status")int status,@Param("companyName") String companyName,@Param("brandName") String brandName);
最后完成测试类中的测试方法,模拟传入参数传入参数,处理参数(用的是字符串类型的拼接)
@Test public void selectByCondition(){ // 接收参数 int status=1; String companyName="华为"; String brandName="华为"; // 处理参数 companyName="%"+companyName+"%"; brandName="%"+brandName+"%"; // 1.获取SqlSessionFactory(直接官文复制或者原来的工程中复制) String resource = "com/itheima/mappers/mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取SqlSession对象 SqlSession sqlSession= sqlSessionFactory.openSession(); // 3.获取Mapper接口的代理对象 BrandMapper brandMapper= sqlSession.getMapper(BrandMapper.class); // 执行方法 List<Brand> brands=brandMapper.selectByCondition(status,companyName,brandName); System.out.println(brands); // 释放资源 sqlSession.close(); }
2.对象
接口中的方法
List<Brand> selectByCondition(Brand brand);
测试类
// 封装对象 Brand brand=new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); // 执行方法 List<Brand> brands=brandMapper.selectByCondition(brand);
3.map
接口中的方法
List<Brand> selectByCondition(Map map);
测试类的方法改动地方
// 处理参数 companyName="%"+companyName+"%"; brandName="%"+brandName+"%"; // 封装对象 Map map=new HashMap(); map.put("status",status); map.put("company_name",companyName); map.put("brand_name",brandName); // 执行方法 List<Brand> brands=brandMapper.selectByCondition(map); System.out.println(brands);
多条件-动态条件查询
mybatis专门提供了一些标签来完成动态sql语句,官文写的非常的清楚
其实就是在mybatis在sql语句中实现了加强,这里用上一个练习举例,当用户输入的条件不是三个的时候,我们用上面的代码就无法完成查询,这是个bug所以我们使用mybatis的动态sql更改下SQL语句
<!--动态条件查询--> <select id="selectByCondition" resultMap="brandResultMap"> SELECT* FROM tb_brand WHERE <if test="status!=null">status=#{status} </if> <if test="companyName!=null and companyName!=''">AND company_name LIKE #{companyName} </if> <if test="brandName!=null and brandName!=''">AND brand_name LIKE #{brandName}</if> </select>
其实就是加了条件的判断,注意这里条件间的连接直接使用and
if:逻辑判断标签,test属性:逻辑表达式
随后我们发现即使只传入两个参数仍然可以完成查询
这样还有个bug就是如果第一个值没有的话,运行就会报错因为2,3句sql语句前面有and
解决的方式有两种:
1.sql引入恒等式
第一句前面加AND,在where后加一个恒等式
2.用mybatis提供的where标签替换关键字where
<where> <if test="status!=null"> status=#{status} </if> <if test="companyName!=null and companyName!=''">AND company_name LIKE #{companyName} </if> <if test="brandName!=null and brandName!=''">AND brand_name LIKE #{brandName}</if> </where>
练习4,单条件,动态条件查询
实现用户选择一个条件输入
接口中定义方法
List<Brand> selectByConditionSingle(Brand brand);
写sql语句
</select> <select id="selectByConditionSingle" resultMap="brandResultMap"> SELECT * FROM tb_brand WHERE <choose> <when test="status!=null"> status=#{status} </when> <when test="companyName!=null and companyName!=''"> AND company_name LIKE #{companyName} </when> <when test="brandName!=null and brandName!=''"> AND brand_name LIKE #{brandName} </when> <otherwise>1=1</otherwise> </choose> </select>
这里的choose相当于java中的switch,when就相当于case
这里的otherwise表示其他情况,就是用户一个条件都不选直接点击查询
也可以不用otherwise直接使用where标签将这些语句包裹就好了
配置文件完成增删改查
完成用户直接增添数据
1.添加接口方法
void add(Brand brand);
2.完成sql语句
<insert id="add"> INSERT INTO tb_brand(brand_name, company_name, ordered, description, status) VALUES (#{brandName},#{companyName},#{ordered},#{description},#{status}) </insert>
3.测试方法编写
@Test public void add(){ // 接收参数 int status=1; String companyName="菠萝手机"; String brandName="菠萝"; String description="美国有苹果,中国有菠萝,支持菠萝手机"; int ordered=100; // 处理参数 companyName="%"+companyName+"%"; brandName="%"+brandName+"%"; // 封装对象 Brand brand=new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); brand.setDescription(description); brand.setOrdered(ordered); // 1.获取SqlSessionFactory(直接官文复制或者原来的工程中复制) String resource = "com/itheima/mappers/mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取SqlSession对象 SqlSession sqlSession= sqlSessionFactory.openSession(); // 3.获取Mapper接口的代理对象 BrandMapper brandMapper= sqlSession.getMapper(BrandMapper.class); // 执行方法 brandMapper.add(brand); // 释放资源 sqlSession.close(); }
这里可以运行但是发现数据添加不成功,但是这里时自动回滚,你再添加数据id会直接加2
注意这里需要手动提交下事务,如果数据添加不成功的话
添加主键返回
我们添加了商品信息后如果想要得到其id以便归类到另外一张表里时,以上面的代码要想直接得到没有传入而是自动生成的主键的值是无法得到的,这时候就要在sql里面添加两个属性来完成
修改数据
1.定义接口方法
void update(Brand brand);
2。书写sql语句
<update id="update"> UPDATE tb_brand SET brand_name=#{brandName}, company_name=#{companyName}, ordered=#{ordered}, description=#{description}, status=#{status} WHERE id=#{id} </update>
3.测试方法
@Test public void update(){ // 接收参数 int id=4; int status=1; String companyName="小米手机"; String brandName="小米"; String description="小米手机为梦发热"; int ordered=10000; // 处理参数 // companyName="%"+companyName+"%"; // brandName="%"+brandName+"%"; // 封装对象 Brand brand=new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); brand.setDescription(description); brand.setOrdered(ordered); brand.setId(id); // 1.获取SqlSessionFactory(直接官文复制或者原来的工程中复制) String resource = "com/itheima/mappers/mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取SqlSession对象 SqlSession sqlSession= sqlSessionFactory.openSession(); // 3.获取Mapper接口的代理对象 BrandMapper brandMapper= sqlSession.getMapper(BrandMapper.class); // 执行方法 brandMapper.update(brand); // 提交事务 sqlSession.commit(); // 释放资源 sqlSession.close(); }
这样只能静态修改,即传入除主键外的·所有变量,不能传入任意变量
我们修改下sql语句,用mybatis自带的set标签完成动态修改
<update id="update"> UPDATE tb_brand <set> <if test="brandName!=null and brandName!=''">brand_name=#{brandName},</if> <if test="companyName!=null and companyName!=''">company_name=#{companyName},</if> <if test="ordered!=null">ordered=#{ordered},</if> <if test="description!=null and description!=''">description=#{description},</if> <if test="tatus!=null">status=#{status}</if> </set> WHERE id=#{id} </update>
这里就完成了动态修改
删除功能
因为普通单个删除太简单了,直接联系批量动态删除
1.编写接口中的方法
这里使用了注解@param是因为mybatis会自动将数组传入整合成map对象,我们后来便利的时候要通过key(默认的是array)来遍历,所以我们将array改成ids
2.写sql方法
<delete id="deleteByIds"> DELETE FROM tb_brand WHERE id IN( <foreach collection="ids" item="id" separator=",">#{id}</foreach> ); </delete>
这里使用了mybatis提供的动态sql中的foreach标签来遍历,key是ids,这些属性的含义是将对应值付给占位符id,每个值用,隔开
3.写测试
MyBatis参数传递底层原理
MyBatis接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式
看这个源码对参数传递的理解有帮助
如果是多个参数,mybatis将参数封装成Map集合
其中3点之后都是用@Param注解比较好
使用注解完成增删改查
注解可以完成简单的增删改查功能,但是对于复杂的功能(动态sql)还是使用配置文件
官文呢是这样描述的
注解开发小案例
直接在写接口方法的时候将对应的sql语句写道注解后面,那么就不用在sql的配置文件里写了主要的注解有
@Select @Update @Insert @Delete
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术