mybatis入门
MyBatis开发步骤:
1,导入mybatis的坐标的相关坐标
2.创建数据库表
3.创建数据库表对应的实体类
4.编写映射配置文件
5.编写核心配置文件
6.进行测试
1,导入mybatis的坐标的相关坐标
<dependencies> <!-- 引入mysql的依赖,操作数据库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <!-- 引入mybatis的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- 引入单元测试junit的依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--引入日志文件log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
2.创建数据库表(这里以user表为例)
3.创建数据库表对应的实体类
package com.yingfengshaonian.domain; /** * @Author zyh * @Date 2021年05月25日 9:38 * @Description //TODO * @Version 1.0 */ public class User { private Integer id; private String userName; private String passWord; public Integer getId() { return id; } public void setId(Integer 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 + '\'' + '}'; } }
4.编写映射配置文件
一般我们的映射配置文件是要在resources文件下面创建一个和表对应的实体类的相同的目录结构,最后一层目录可以不同,这样方便查看结构.
映射配置文件的内容如下:
<?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="userMapper"> <select id="findAll" resultType="com.yingfengshaonian.domain.User"> select * from user </select> </mapper>
5.编写核心配置文件
核心配置文件我们直接放在resource目录下面,方便我们后续的加载
核心配置文件的内容如下:
<?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的核心配置文件,配置mybatis的各种核心配置--> <!-- resource标签直接加载的是resources目录下的文件--> <properties resource="jdbc.properties"></properties> <!-- 配置数据源环境--> <environments default="dev"> <environment id="dev"> <!-- 使用JDBC原生的事务管理器 --> <transactionManager type="JDBC"></transactionManager> <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> <!-- 加载映射配置文件--> <mappers> <mapper resource="com/yingfengshaonian/mapper/UserMapper.xml"></mapper> </mappers> </configuration>
6.进行测试
下面是测试的代码:
package com.yingfengshaonian.test; import com.yingfengshaonian.domain.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 org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; /** * @Author zyh * @Date 2021年05月25日 10:04 * @Description //TODO * @Version 1.0 */ public class MybatisTest { @Test public void befprTest() throws IOException { // 加载核心配置文件成流 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); // 获得session工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获得session会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过会话对象进行操作 List<User> userList = sqlSession.selectList("userMapper.findAll"); // 打印集合查看结果 System.out.println(userList); // 关闭会话,释放资源 sqlSession.close(); } }
其实这样的开发在我们的工作中是基本上不会使用的我们使用的更多的是mybatis的接口代理的模式进行开发
核心配置文件的概述
mybatis的核心配置文件配置的是使用mybatis框架的时候对框架的一些属性和环境的配置,是mybatis框架运行的基础,mybatis的配置中,对应的配置都有自己的标签,而且这些标签的配置顺序是有所规定的,我们不能违反他的默认配置顺序
核心配置文件的配置顺序是:
configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
大概的介绍为:
- configuration配置
- properties属性(可以加在properties文件)
- settings设置
- typeAliases类型别名
- typeHandlers类型处理器
- objectFactory对象工厂
- plugins插件
- environments环境
- .environment环境变量
- transactionManager事务管理器
- datasource数据源
- .environment环境变量
- databaseldProvider数据库厂商标识
- mappers映射器
详细可以参考博文:https://blog.csdn.net/modao_huohuo/article/details/107706555
mybatis的代理开发模式
1·代理开发方式介绍
采用Mybatis的代理开发方式实现DAO层的开发,这种方式是我们后面进入企业的主流,
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),
由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
mapper接口开发需要遵循以下规范
1,Mapper.xml文件中的namespace与mapper接口的全限定名相同
2,Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3,Mapper接口方法的输入参数类型和mapper.xml中定义的每个sq的parameterType的类型相同
4,Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
在我们满足上面四种规范的情况下,mybatis的代理模式中就会自动帮我们创建实体类mapper接口的实现类,实现类的执行逻辑的操作是在对应的接口的映射配置文件中完成的
所以我们在上面项目结构的基础上创建一个UserMapper接口:
package com.yingfengshaonian.mapper; import com.yingfengshaonian.domain.User; import java.util.List; public interface UseMapper { List<User> findAll(); }
然后在User的映射配置文件中完成上面的四种规范
<?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="com.yingfengshaonian.mapper.UseMapper"> <select id="findAll" resultType="com.yingfengshaonian.domain.User"> select * from user </select> </mapper>
我们在测试类中使用的操作方法就会有所改变:
package com.yingfengshaonian.test; import com.yingfengshaonian.domain.User; import com.yingfengshaonian.mapper.UseMapper; 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 org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; /** * @Author zyh * @Date 2021年05月25日 10:04 * @Description //TODO * @Version 1.0 */ public class MybatisTest { @Test public void befprTest() throws IOException { // 加载核心配置文件成流 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); // 获得session工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获得session会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过会话对象获得代理对象,那么这个代理对象就含有这个依据获得接口(在这里也就是UserMapper)的全部办法 UseMapper mapper = sqlSession.getMapper(UseMapper.class); List<User> userList = mapper.findAll(); System.out.println(userList); // 关闭会话,释放资源 sqlSession.close(); } }
所以当我们使用代理模式进行开发时,我们主要的方法的执行逻辑是编写在映射配置文件中的,如果涉及的负责的语句,我们就需要学习动态sql的知识:
映射配置文件动态sql
if语句
当我们根据传输的对象进行查询的时候,如果这个对象的属性是不确定的,那么对应的我们的查询语句的生成也不能写成固定的,
那么就需要我们的代理对象在方法中动态的生成sql语句:
<select id="findByUserDTO" resultType="com.yingfengshaonian.domain.User" parameterType="com.yingfengshaonian.domain.User"> select * FROM user <where> <if test="id !=null"> and id =#{id} </if> <if test="userName!=null"> and username=#{userName} </if> <if test="passWord!=null"> and password=#{passWord} </if> </where>; </select>
当我们传入的对象的属性含有id,userName,passWord全部属性的值的时候,
UseMapper mapper = sqlSession.getMapper(UseMapper.class); User userDTO = new User(); userDTO.setId(1); userDTO.setUserName("小红"); userDTO.setPassWord("123"); List<User> userList = mapper.findByUserDTO(userDTO); System.out.println(userList);
对应的sql查询语句是:
2021-05-25 13:29:59,107 main DEBUG findByUserDTO:159 - ==> Preparing: select * FROM user WHERE id =? and username=? and password=? ;
2021-05-25 13:29:59,206 main DEBUG findByUserDTO:159 - ==> Parameters: 1(Integer), 小红(String), 123(String)
2021-05-25 13:29:59,253 main DEBUG findByUserDTO:159 - <== Total: 1
[User{id=1, userName='小红', passWord='123'}]
当出入的对象的属性只有id和userName的时候:
User userDTO = new User(); userDTO.setId(1); userDTO.setUserName("小红"); // userDTO.setPassWord("123"); List<User> userList = mapper.findByUserDTO(userDTO); System.out.println(userList);
执行的sql语句是:
2021-05-25 13:35:24,947 main DEBUG findByUserDTO:159 - ==> Preparing: select * FROM user WHERE id =? and username=? ;
2021-05-25 13:35:25,054 main DEBUG findByUserDTO:159 - ==> Parameters: 1(Integer), 小红(String)
2021-05-25 13:35:25,096 main DEBUG findByUserDTO:159 - <== Total: 1
[User{id=1, userName='小红', passWord='123'}]
可以看出语句根据属性传入属性的不同完成了自动的变化
foreach语句
当我们根据某一个字段的多个值查询多个结果的时候,原始的sql语句就是:select * from user WHERE id in( ? , ? , ? )
我们实现这种关系需要用到foreach语句:
<select id="findIdList" resultType="com.yingfengshaonian.domain.User" parameterType="list"> select * from user <where> <foreach collection="list" item="id" open="id in(" close=")" separator=","> #{id} </foreach> </where> </select>
对foreach标签属性的解释
- collection
如果传入的字段集是集合,collection的值就是list,如果传入的字段集是集合传入的字段集是数组collection的值就是array
- item
对集合中每一元素遍历是的临时引用,相当于foreach(int id : list)中的id
- open
where语句后面的开始标记
- close
语句关闭的标记
- separator
分隔符
当集合中的元素是1,2,3的时候
List<Integer> list =new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); List<User> userList = mapper.findIdList(list); System.out.println(userList); // 关闭会话,释放资源 sqlSession.close();
查询的sql语句是:
2021-05-25 13:51:27,541 main DEBUG findIdList:159 - ==> Preparing: select * from user WHERE id in( ? , ? , ? )
2021-05-25 13:51:27,617 main DEBUG findIdList:159 - ==> Parameters: 1(Integer), 2(Integer), 3(Integer)
2021-05-25 13:51:27,663 main DEBUG findIdList:159 - <== Total: 3
[User{id=1, userName='小红', passWord='123'}, User{id=2, userName='小明', passWord='456'}, User{id=3, userName='小刚', passWord='789'}]
当元素只有1,2的时候
List<Integer> list =new ArrayList<Integer>(); list.add(1); list.add(2); // list.add(3); List<User> userList = mapper.findIdList(list); System.out.println(userList); // 关闭会话,释放资源 sqlSession.close();
输出的sql语句是:
2021-05-25 14:08:23,812 main DEBUG findIdList:159 - ==> Preparing: select * from user WHERE id in( ? , ? ) 2021-05-25 14:08:23,891 main DEBUG findIdList:159 - ==> Parameters: 1(Integer), 2(Integer) 2021-05-25 14:08:23,927 main DEBUG findIdList:159 - <== Total: 2 [User{id=1, userName='小红', passWord='123'}, User{id=2, userName='小明', passWord='456'}]
可以看出来sql语句的生成也是动态的
多表操作
一对一
一对一操作比较经典的是订单表和用户表,一对一的情况是每一个订单都对应有一个用户,当然还有另一种情况就是每一个用户都有若干个订单,那是鼠疫一对多的操作,现在我们讲解一对一的操作.
我们需要创建一个新的表,orders:
再在项目中添加这个表对应的实体类等相关操作(这里不做演示,需要注意的是我们需要在order类中添加user的属性)
Oeder类如下:
package com.yingfengshaonian.domain; import java.util.Date; /** * @Author zyh * @Date 2021年05月26日 13:48 * @Description //TODO * @Version 1.0 */ public class Order { private Integer id; private Date orderTime; private Double total; private Integer uid; private User user;//这里需要注意 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Date getOrderTime() { return orderTime; } public void setOrderTime(Date orderTime) { this.orderTime = orderTime; } public Double getTotal() { return total; } public void setTotal(Double total) { this.total = total; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
如果我们需要查询全部的订单包含他们的order,使用的sql语句是:SELECT user.`password`,user.`username`,orders.`id`,orders.`order_time`,orders.`total`,orders.`uid` FROM USER ,orders WHERE orders.`uid`=user.`id` 查询出来的结果是
我们需要使用结果集映射来实现对查询结果和实体类字段的映射;
关于结果映射的理解:
我们使用的查询语句查询出来的结果是需要封装到对应的我们自己定义的实体类之中的,比如我们使用简单的单表查询的时候,我们使用的查询语句返回的数据库中的几乎所有的字段都是实体类之中的,mybatis默认使用的是属性名和字段名(不区分大小写)的自动填充机制,我们使用多表查询的时候很难做到我们的查询结果和我们的对象的属性的名称是一一对应的,所以我们需要自己指定查询结果字段和类的属性的对应关系,也就是结果集映射.
批量插入
参考博文:
https://blog.csdn.net/wsjzzcbq/article/details/81779588