MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
使用mybatis框架来替代原始JDBC的开发。mybatis把连接资源放在内部,想要用直接拿,用完还回来即可,有效的解决了JDBC频繁的创建、释放连接资源。而且我们使用mybatis框架,当sql语句需要发生改变的,不需要改变JAVA代码,只需要更改一下配置文件即可。
mappers 元素则包含了一组映射器(mapper),这些映射器的 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"> <mapper namespace="userMapper"> <select id="findAll" resultType="com.liu.domain.User"> select *from user </select> </mapper>XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 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"> <!--配置一个id为development的环境--> <environment id="development"> <!--使用JDBC事务--> <transactionManager type="JDBC"/> <!--数据库连接池--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///stu?useSSL=false&useUnicode=true&characterEconding=UTF-8&allowPublicKeyRetrieval=true"/> <property name="username" value="root"/> <property name="password" value="131411"/> </dataSource> </environment> </environments> <!--加载映射文件--> <mappers> <mapper resource="com.liu.mapper/UserMapper.xml"/> </mappers> </configuration>当然,还有很多可以在 XML 文件中配置的选项,上面的示例仅罗列了最关键的部分。 注意 XML 头部的声明,它用来验证 XML 文档的正确性。environment 元素体中包含了事务管理和连接池的配置。
进行测试是否成功
@Test public void test01() throws IOException { //读取mybatis的配置文件得到配置文件流 InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //根据配置文件信息,创建会话工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //通过工厂得到SqlSession对象 SqlSession sqlSession = factory.openSession(); //通过sqlSession对象执行映射文件中定义的SQL,并返回映射结果 List<User> list = sqlSession.selectList("userMapper.findAll"); System.out.println(list); //关闭sqlSession,释放资源 sqlSession.close(); }运行结果展示:
如果通过上述代码来写的话,可以发现有很多的代码是重复的。所以我们使用JUnit的@Before来创建sqlSession对象以及通过@After来关闭sqlSession,释放资源。
import com.liu.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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test1 { private SqlSessionFactory sqlSessionFactory; private SqlSession sqlSession; @Before public void init(){ //读取mybatis的配置文件得到配置文件流 InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //根据配置文件信息,创建会话工厂 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //通过工厂得到SqlSession对象 sqlSession = sqlSessionFactory.openSession(); } catch (IOException e) { e.printStackTrace(); } } //查询用户 @Test public void test01() throws IOException { //通过sqlSession对象执行映射文件中定义的SQL,并返回映射结果 List<User> list = sqlSession.selectList("userMapper.findAll"); System.out.println(list); } //添加用户 @Test public void test02(){ User user = new User(); user.setId(10); user.setUsername("一球"); user.setEmail("314131@dwq"); user.setPassword("131411"); user.setPhoneNum("13461460194"); int insert = sqlSession.insert("userMapper.addUser",user); System.out.println(insert); } //删除用户 @Test public void test03(){ int i = sqlSession.delete("userMapper.deleteByName", 10); System.out.println(i); } //更改用户 @Test public void test04(){ int update = sqlSession.update("userMapper.updateById", new User(3, "嘻嘻嘻嘻嘻", "dd", "ddd", "ddd")); System.out.println(update); } @After public void destory(){ //提交事务 sqlSession.commit(); //关闭sqlSession,释放资源 sqlSession.close(); } }通过上述mybatis快速入门你会发现,我根本就没编写Dao层呀。到时候我该如何和service层进行交互呢?但这也发现了mybatis的神奇之处:mybatis不需要Dao层就可以实现增删改查。接下来让我们看一看如何使用mybatis来实现Dao层。
即首先创建一个UserDao接口,在接口中编写业务方法。通过UserDaoImpl这个类来实现UserDao的方法,从而把数据返回给Service层的UserServiceImpl。
UserDao接口:
public interface UserDao { List<User> findAll() throws IOException; }UserDaoImpl接口实现:
public class UserDaoImpl implements UserDao { public List<User> findAll() throws IOException { InputStream resourceAsStream =Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> userList = sqlSession.selectList("userMapper.findAll"); sqlSession.close(); return userList; } }采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。 Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。 Mapper 接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的全限定名相同
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
例如:
UserDao接口:
public interface UserDao { List<User> findAll(); }mapper.xml映射文件:
<mapper namespace="com.liu.dao.UserDao"> <!--查询所有--> <select id="findAll" resultType="com.liu.POJO.User"> select *from user </select>UserServiceImpl测试:
public class UserServiceImpl { public static void main(String[] args) throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.findAll(); System.out.println(userList); }结果:
点击可直接进入官网详细查看:
configuration(配置)
properties(属性)
properties:用于读取properties配置文件
<!--加载属性文件--> <properties resource="jdbc.properties"/> jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql:///stu?useSSL=false&useUnicode=true&characterEconding=UTF-8&allowPublicKeyRetrieval=true jdbc.user=root jdbc.password=131411settings(设置)
settings:一般我们用来配置日志文件
配置使用log4j日志文件
#���ȼ�ΪDEBUG����־��Ϣ�����console��file������Ŀ�ĵأ�console��file�Ķ���������Ĵ��� log4j.rootLogger=DEBUG,console #����̨������������ log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #��־������� log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUGtypeAliases(类型别名)
一般用于给类起别名
<!--给包中的类注册别名--> <typeAliases> <typeAlias type="com.liu.pojo.User" alias="User"/> <typeAlias type="com.liu.pojo.Orders" alias="Orders"/> </typeAliases>typeHandlers(类型处理器)
一般使用自带的类型处理器,但是当想对数据进行更改操作时可以更改重写类型处理器
eg:数据库中的DateTime类型想输出时为Date
objectFactory(对象工厂)
plugins(插件)
插件有很多,可以配置一个很常用的分页查询插件
mybatis-config.xml配置如下:
<!--配置分页助手插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageHelper"> <property name="dialect" value="mysql"/> </plugin> </plugins>但是这个插件需要引入坐标
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>3.7.5</version> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>0.9.1</version> </dependency>使用的时候只需要写一行代码
//设置分页相关参数 当前页+每页要显示的个数 PageHelper.startPage(1,3);environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
一般我们配置的都是JDBC事务管理器
dataSource(数据源)
dataSource配置获取
<!--数据源环境--> <environments default="development"> <!--配置一个id为development的环境--> <environment id="development"> <!--使用JDBC事务--> <transactionManager type="JDBC"/> <!--数据库连接池--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments>databaseIdProvider(数据库厂商标识)
这个几乎没用过
mappers(映射器)
超级重要!!!用来加载Mapper.xml文件的!!!
<!--加载映射文件--> <mappers> <mapper resource="UserMapper.xml"/> <mapper resource="OrdersMapper.xml"/> </mappers>最重要的就是下面这几块了!!!
这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。
<!--Sql片段的抽取--> <sql id="sqlSelect">select *from user</sql>这里我只列出了我认为十分重要的属性,以及他们的描述:
属性描述id在命名空间中唯一的标识符,可以被用来引用这条语句。parameterType**描述将会传入这条语句的参数的类全限定名或别名。**这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。resultMap**对外部 resultMap 的命名引用。**结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。eg:在mapper.xml配置文件中写入
<!--查询所有--> <select id="findAll" resultType="com.liu.dao.User"> select *from user </select>默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。
动态SQL:根据不同条件拼接 SQL 语句
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。
<!--动态SQL--> <select id="findBySome" resultType="com.liu.pojo.User" parameterType="com.liu.pojo.User"> select *from user <where> <if test="id!=null"> id=#{id} </if> <if test="username!=null"> and username=#{username} </if> <if test="password!=null"> and password=#{password} </if> </where> </select>测试:
public static void main(String[] args) throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); User user = new User(); user.setId(1); user.setUsername("GG"); User user1 = new User(); user1.setId(2); List<User> userList = mapper.findBySome(user); System.out.println(userList); List<User> bySome = mapper.findBySome(user1); System.out.println(bySome); sqlSession.close(); }[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nOPOdgdj-1603351515606)(https://shop.io.mi-img.com/app/shop/img?id=shop_177e47475fd61ba1217cc93fcaeb2891.png)]
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
<!--通过多个id查询用户数据--> <select id="findByIds" parameterType="list" resultType="com.liu.pojo.User"> select *from user <where> <foreach collection="list" open="id in(" close=")" item="id" separator=","> #{id} </foreach> </where> </select>测试:
public static void main(String[] args) throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(10); arrayList.add(1); List<Integer> arrayList1 = new ArrayList<Integer>(); arrayList1.add(2); arrayList1.add(4); List<User> mapperByIds = mapper.findByIds(arrayList); for (User mapperById : mapperByIds) { System.out.println(mapperById); } List<User> userList = mapper.findByIds(arrayList1); for (User user : userList) { System.out.println(user); } sqlSession.close(); }[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vjWTBTBT-1603351515608)(https://shop.io.mi-img.com/app/shop/img?id=shop_65178e8af9b99cffec88dcc3150d1888.png)]
接下来的就是重点啦~
学会使用了简单的Crud,现在有一个问题出现在我们面前。上述说的crud都是单表的操作,那么双表的操作该如何用mybatis实现呢?
多表操作无非就是三种:一对一,一对多,多对多
一对一我们应该要如何实现呢?
这里是关于用户和订单的业务,我们要查询每个订单的用户都是谁。我们该如何去做呢?
1.这时我们需要把要查询的用户 给封装成订单的一个属性并生成get/set方法
public class Orders { private int id; private Date orderTime; private int total; //注意看这:*****把用户封装成订单的一个属性 private User user; //重写toString方法 @Override public String toString() { return "Orders{" + "id=" + id + ", orderTime=" + orderTime + ", total=" + total + ", user=" + user + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public Date getOrderTime() { return orderTime; } public void setOrderTime(Date orderTime) { this.orderTime = orderTime; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } //生成get/set public User getUser() { return user; } public void setUser(User user) { this.user = user; } }2.创建OrdersDao,并且写一个查询抽象方法。
public interface OrdersDao { List<Orders> findAll(); }3.在OrdersMapper.xml中进行配置:
这里的结果集我们需要自己进行封装,所以我们不能用resultType
我们需要使用resultMap进行自己封装
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。**
resultMap包含的元素:
<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性--> <resultMap id="唯一的标识" type="映射的pojo对象"> <id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" /> <result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/> <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象"> <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/> <result column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/> </association> <!-- 集合中的property须为oftype定义的pojo对象的属性--> <collection property="pojo的集合属性" ofType="集合中的pojo对象"> <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" /> <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" /> </collection> </resultMap> <resultMap id="findUserOrder" type="Orders"> <!--手动指定字段与实体属性的映射关系 column:数据库的字段名称 property:实体的属性名称 --> <id column="oid" property="id"/> <result column="orderTime" property="orderTime"/> <result column="total" property="total"/> <result column="uid" property="user.id"/> <result column="username" property="user.username"/> <result column="email" property="user.email"/> <result column="password" property="user.password"/> <result column="phoneNum" property="user.phoneNum"/> </resultMap> <select id="findAll" resultMap="findUserOrder"> SELECT *,u.id usid,o.id oid from user u,orders o where u.id=o.uid; </select>上面的配置使用逻辑不好,请看下面的逻辑
<resultMap id="findUserOrder" type="Orders"> <!--手动指定字段与实体属性的映射关系 column:数据库的字段名称 property:实体的属性名称 --> <id column="oid" property="id"/> <result column="orderTime" property="orderTime"/> <result column="total" property="total"/> <!-- association标签: property:当前实体中的属性名称(private User user) javaType:当前实体中属性的类型(User) --> <association property="user" javaType="User"> <id column="uid" property="id"/> <result column="username" property="username"/> <result column="email" property="email"/> <result column="password" property="password"/> <result column="phoneNum" property="phoneNum"/> </association> </resultMap> <select id="findAll" resultMap="findUserOrder"> SELECT *,u.id usid,o.id oid from user u,orders o where u.id=o.uid; </select>4.测试:
//一对一多表查询 @Test public void TestFindAll(){ OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class); List<Orders> ordersList = ordersDao.findAll(); for (Orders orders : ordersList) { System.out.println(orders); } sqlSession.close(); }一对多的过程与一对一的过程只差了一点点:
业务:一个User有多个Order,要查询User的Order
1.我们首先在User里要封装一个list集合,这个集合的泛型是Order类型
package com.liu.pojo; import java.util.List; public class User { private int id; private String username; private String email; private String password; private String phoneNum; //描述的是当前用户存在哪些订单 private List<Orders> orders; //生成get/set方法 public List<Orders> getOrders() { return orders; } public void setOrders(List<Orders> orders) { this.orders = orders; } public User() { } public User(int id, String username, String email, String password, String phoneNum) { this.id = id; this.username = username; this.email = email; this.password = password; this.phoneNum = phoneNum; } //重写toString方法 @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", email='" + email + '\'' + ", password='" + password + '\'' + ", phoneNum='" + phoneNum + '\'' + ", orders=" + orders + '}'; } 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 getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPhoneNum() { return phoneNum; } public void setPhoneNum(String phoneNum) { this.phoneNum = phoneNum; } }2.在UserDao中创建一个方法
public interface UserDao { List<User> findOrders(); }3.在UserMapper.xml中进行配置
因为orders属性是一个集合,所以要用到resultMap的collection标签:
<!-- 集合中的property须为oftype定义的pojo对象的属性--> <collection property="pojo的集合属性" ofType="集合中的pojo对象"> <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" /> <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" /> </collection>配置如下:
<resultMap id="userFindOrders" type="User"> <id column="uid" property="id"/> <result column="username" property="username"/> <result column="email" property="email"/> <result column="password" property="password"/> <result column="phoneNum" property="phoneNum"/> <collection property="orders" ofType="Orders"> <id column="oid" property="id"/> <result column="orderTime" property="orderTime"/> <result column="total" property="total"/> </collection> </resultMap> <select id="findOrders" resultMap="userFindOrders"> select *,o.id oid,u.id uid from user u,orders o where u.id=o.uid; </select>4.进行Test测试
//一对多查询 @Test public void TestUserFindOrders(){ UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.findOrders(); for (User user : userList) { System.out.println(user); } sqlSession.close(); }多对多的查询与一对多几乎是一样的,除了多了一个中间表
业务介绍:我们现在有一张user表,一张role表,还有一张连接表userrole。现在我们需要知道User是什么职位的。
1.首先封装一个list集合,一个user可能有多个role,而一个role可能有多个user。所以我们需要封装一个List,泛型为role.
Role类:
package com.liu.pojo; public class Role { private int id; private String rolename; private String roleDesc; @Override public String toString() { return "Role{" + "id=" + id + ", rolename='" + rolename + '\'' + ", roleDesc='" + roleDesc + '\'' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getRolename() { return rolename; } public void setRolename(String rolename) { this.rolename = rolename; } public String getRoleDesc() { return roleDesc; } public void setRoleDesc(String roleDesc) { this.roleDesc = roleDesc; } }User类
package com.liu.pojo; import java.util.List; public class User { private int id; private String username; private String email; private String password; private String phoneNum; //描述的是当前用户存在哪些订单 private List<Orders> orders; //查询当前用户有几个职位 private List<Role> roleList; public List<Role> getRoleList() { return roleList; } public void setRoleList(List<Role> roleList) { this.roleList = roleList; } public List<Orders> getOrders() { return orders; } public void setOrders(List<Orders> orders) { this.orders = orders; } public User() { } public User(int id, String username, String email, String password, String phoneNum) { this.id = id; this.username = username; this.email = email; this.password = password; this.phoneNum = phoneNum; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", email='" + email + '\'' + ", password='" + password + '\'' + ", phoneNum='" + phoneNum + '\'' + ", orders=" + orders + ", roleList=" + roleList + '}'; } 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 getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPhoneNum() { return phoneNum; } public void setPhoneNum(String phoneNum) { this.phoneNum = phoneNum; } }2.在UserDao创建一个方法
public interface UserDao { List<User> findUserAndRoleAll(); }3.在UserMapper.xml进行配置
<resultMap id="UserAndRole" type="User"> <id column="userId" property="id"/> <result column="username" property="username"/> <result column="email" property="email"/> <result column="password" property="password"/> <result column="phoneNum" property="phoneNum"/> <collection property="roleList" ofType="Role"> <id column="roleId" property="id"/> <result property="rolename" column="rolename"/> <result property="roleDesc" column="roleDesc"/> </collection> </resultMap> <select id="findUserAndRoleAll" resultMap="UserAndRole"> SELECT * from `user` u,role r,userrole ur where u.id=ur.userId and r.id=ur.roleId; </select>4.测试:
//测试多对多查询 @Test public void TestUserAndRole(){ UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userAndRoleAll = mapper.findUserAndRoleAll(); for (User user : userAndRoleAll) { System.out.println(user); } sqlSession.close(); } [com.liu.dao.UserDao.findUserAndRoleAll]-==> Preparing: SELECT * from `user` u,role r,userrole ur where u.id=ur.userId and r.id=ur.roleId; [com.liu.dao.UserDao.findUserAndRoleAll]-==> Parameters: [com.liu.dao.UserDao.findUserAndRoleAll]-<== Total: 4 User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=1, rolename='院长', roleDesc='负责所有'}, Role{id=2, rolename='研究员', roleDesc='课程研发'}, Role{id=3, rolename='dd', roleDesc='dd'}]} User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=4, rolename='辅导员', roleDesc='帮助学生进行学习、生活等等'}]} [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2145b572] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2145b572] [org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 558216562 to pool.每一个框架肯定是要有注解的,所以我们需要学习注解开发来简易开发流程。
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
配置mybatis-config.xml核心配置文件:加载映射关系TODO
<!--加载映射关系 TODO--> <mappers> <package name="com.liu.dao"/> </mappers>基本注解的使用:
public interface UserDao { @Select("select *from user") List<User> findAll(); @Select("select *from user where id=#{id}") User findById(int id); @Update("update user set username=#{username} where id=#{id}") int updateUser(User user); @Insert("insert into user values (#{id},#{username},#{email},#{password},#{phoneNum})") int insertUser(User user); @Delete("delete from user where id=#{id}") int deleteUser(int id); }基本注解测试:
public class Test01 { private SqlSessionFactory sqlSessionFactory; private SqlSession sqlSession; @Before public void init(){ //读取mybatis的配置文件得到配置文件流 InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //根据配置文件信息,创建会话工厂 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //通过工厂得到SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); } catch (IOException e) { e.printStackTrace(); } } @After public void delect(){ sqlSession.close(); } @Test public void save(){ User user = new User(); user.setId(13); user.setUsername("哈哈"); user.setPassword("131411"); user.setEmail("7733333@qq.com"); user.setPhoneNum("13141414"); UserDao mapper = sqlSession.getMapper(UserDao.class); int i = mapper.insertUser(user); System.out.println(i); } @Test public void findUser(){ UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.findAll(); for (User user : userList) { System.out.println(user); } } @Test public void findByIdUser(){ UserDao userDao = sqlSession.getMapper(UserDao.class); User users = userDao.findById(1); System.out.println(users); } @Test public void deleteUser(){ UserDao userDao = sqlSession.getMapper(UserDao.class); int i = userDao.deleteUser(13); System.out.println(i); } @Test public void updateUser(){ UserDao userDao = sqlSession.getMapper(UserDao.class); User user = new User(); user.setId(1); user.setUsername("Hello!!!"); int i = userDao.updateUser(user); System.out.println(i); } }实现复杂关系映射之前我们可以在映射文件中通过配置resultMap来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
注解说明@Results代替的是标签resultMap该注解中可以使用单个@Result注解,也可以使用@Result集合。使用格式:@Results({@Result(),@Result()})或@Results(@Result())@Resut代替了id标签和result标签 @Result中属性介绍: column:数据库的列名 property:需要装配的属性名 one:需要使用的@One 注解(@Result(one=@One)())) many:需要使用的@Many 注解(@Result(many=@many)())) 注解说明@One (一对一)代替了assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。 @One注解属性介绍: select: 指定用来多表查询的 sqlmapper使用格式:@Result(column=" “,property=”",one=@One(select=""))@Many (多对一)代替了collection标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。 使用格式:@Result(property="",column="",many=@Many(select=""))测试:
@Test public void findOrderAndUser(){ OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class); List<Orders> ordersList = ordersDao.findAllAndUser(); for (Orders orders : ordersList) { System.out.println(orders); } }日志文件:
[com.liu.dao.OrdersDao.findAllAndUser]-==> Preparing: SELECT * from orders [com.liu.dao.OrdersDao.findAllAndUser]-==> Parameters: [com.liu.dao.UserDao.findById]-====> Preparing: select *from user where id=? [com.liu.dao.UserDao.findById]-====> Parameters: 1(Integer) [com.liu.dao.UserDao.findById]-<==== Total: 1 [com.liu.dao.UserDao.findById]-====> Preparing: select *from user where id=? [com.liu.dao.UserDao.findById]-====> Parameters: 2(Integer) [com.liu.dao.UserDao.findById]-<==== Total: 1 [com.liu.dao.OrdersDao.findAllAndUser]-<== Total: 3 Orders{id=1, orderTime=Tue Oct 20 13:00:00 CST 2020, total=3000, user=User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=null}} Orders{id=2, orderTime=Thu Oct 01 13:00:00 CST 2020, total=2000, user=User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=null}} Orders{id=3, orderTime=Fri Oct 09 13:00:00 CST 2020, total=4000, user=User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=null}} [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@be64738] [org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 199640888 to pool.UserDao中创建方法
//多表查询:一对多 @Select("select *from user") @Results({ @Result(id = true,column = "id",property ="id" ), @Result(column = "username",property = "username"), @Result(column = "email",property = "email"), @Result(column = "password",property = "password"), @Result(column = "phoneNum",property = "phoneNum"), @Result( property = "orders", column = "id", javaType =List.class, //这里发现我们要用OrdersDao的findById方法 many = @Many(select = "com.liu.dao.OrdersDao.findById") ) }) List<User> findUserAndRole();OrdersDao方法:把select *from user查到的uid传给这个方法,通过这个方法得到一些Orders,再把这些Order给封装到User的orders属性中。
@Select("select *from orders where uid=#{uid}") List<Orders> findById();测试:
//测试一对多 @Test public void findUserAndRole1(){ UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.findUserAndRole(); for (User user : userList) { System.out.println(user); } }测试日志结果:
[com.liu.dao.UserDao.findUserAndRole]-==> Preparing: select *from user [com.liu.dao.UserDao.findUserAndRole]-==> Parameters: [com.liu.dao.OrdersDao.findById]-====> Preparing: select *from orders where uid=? [com.liu.dao.OrdersDao.findById]-====> Parameters: 1(Integer) [com.liu.dao.OrdersDao.findById]-<==== Total: 2 [com.liu.dao.OrdersDao.findById]-====> Preparing: select *from orders where uid=? [com.liu.dao.OrdersDao.findById]-====> Parameters: 2(Integer) [com.liu.dao.OrdersDao.findById]-<==== Total: 1 [com.liu.dao.OrdersDao.findById]-====> Preparing: select *from orders where uid=? [com.liu.dao.OrdersDao.findById]-====> Parameters: 3(Integer) [com.liu.dao.OrdersDao.findById]-<==== Total: 0 [com.liu.dao.OrdersDao.findById]-====> Preparing: select *from orders where uid=? [com.liu.dao.OrdersDao.findById]-====> Parameters: 4(Integer) [com.liu.dao.OrdersDao.findById]-<==== Total: 0 [com.liu.dao.OrdersDao.findById]-====> Preparing: select *from orders where uid=? [com.liu.dao.OrdersDao.findById]-====> Parameters: 10(Integer) [com.liu.dao.OrdersDao.findById]-<==== Total: 0 [com.liu.dao.OrdersDao.findById]-====> Preparing: select *from orders where uid=? [com.liu.dao.OrdersDao.findById]-====> Parameters: 11(Integer) [com.liu.dao.OrdersDao.findById]-<==== Total: 0 [com.liu.dao.UserDao.findUserAndRole]-<== Total: 6 User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=[Orders{id=1, orderTime=Tue Oct 20 00:00:00 CST 2020, total=3000, user=null}, Orders{id=3, orderTime=Fri Oct 09 00:00:00 CST 2020, total=4000, user=null}], roleList=null} User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=[Orders{id=2, orderTime=Thu Oct 01 00:00:00 CST 2020, total=2000, user=null}], roleList=null} User{id=3, username='嘻嘻嘻嘻嘻', email='eeeeeeeeeeeeee', password='eeeeeeeeeeeee', phoneNum='eeeeeeeeeeeee', orders=[], roleList=null} User{id=4, username='liuchang', email='773395726@qq.com', password='ed', phoneNum='dd', orders=[], roleList=null} User{id=10, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=[], roleList=null} User{id=11, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=[], roleList=null} [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@be64738] [org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 199640888 to pool.UserDao中创建方法
//测试多对多 @Select("select *from user") @Results({ @Result(id = true,column = "id",property ="id" ), @Result(column = "username",property = "username"), @Result(column = "email",property = "email"), @Result(column = "password",property = "password"), @Result(column = "phoneNum",property = "phoneNum"), @Result( property = "roleList", column = "id", javaType =List.class, many = @Many(select = "com.liu.dao.RoleDao.findByUid") )}) List<User> findUserRoleAll();RoleDao方法:把select *from user查到的uid传给这个方法,通过这个方法得到一些Orders,再把这些Order给封装到User的orders属性中。
public interface RoleDao { @Select("select * from role r,userrole ur where r.id=ur.roleId and ur.userId=#{uid}") List<Role> findByUid(int uid); }测试:
//测试多对多 @Test public void findUserAndRoles(){ UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.findUserRoleAll(); for (User user : userList) { System.out.println(user); } }测试日志:
[com.liu.dao.UserDao.findUserRoleAll]-==> Preparing: select *from user [com.liu.dao.UserDao.findUserRoleAll]-==> Parameters: [com.liu.dao.RoleDao.findByUid]-====> Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=? [com.liu.dao.RoleDao.findByUid]-====> Parameters: 1(Integer) [com.liu.dao.RoleDao.findByUid]-<==== Total: 3 [com.liu.dao.RoleDao.findByUid]-====> Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=? [com.liu.dao.RoleDao.findByUid]-====> Parameters: 2(Integer) [com.liu.dao.RoleDao.findByUid]-<==== Total: 1 [com.liu.dao.RoleDao.findByUid]-====> Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=? [com.liu.dao.RoleDao.findByUid]-====> Parameters: 3(Integer) [com.liu.dao.RoleDao.findByUid]-<==== Total: 0 [com.liu.dao.RoleDao.findByUid]-====> Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=? [com.liu.dao.RoleDao.findByUid]-====> Parameters: 4(Integer) [com.liu.dao.RoleDao.findByUid]-<==== Total: 0 [com.liu.dao.RoleDao.findByUid]-====> Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=? [com.liu.dao.RoleDao.findByUid]-====> Parameters: 10(Integer) [com.liu.dao.RoleDao.findByUid]-<==== Total: 0 [com.liu.dao.RoleDao.findByUid]-====> Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=? [com.liu.dao.RoleDao.findByUid]-====> Parameters: 11(Integer) [com.liu.dao.RoleDao.findByUid]-<==== Total: 0 [com.liu.dao.UserDao.findUserRoleAll]-<== Total: 6 User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=1, rolename='院长', roleDesc='负责所有'}, Role{id=2, rolename='研究员', roleDesc='课程研发'}, Role{id=3, rolename='dd', roleDesc='dd'}]} User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=4, rolename='辅导员', roleDesc='帮助学生进行学习、生活等等'}]} User{id=3, username='嘻嘻嘻嘻嘻', email='eeeeeeeeeeeeee', password='eeeeeeeeeeeee', phoneNum='eeeeeeeeeeeee', orders=null, roleList=[]} User{id=4, username='liuchang', email='773395726@qq.com', password='ed', phoneNum='dd', orders=null, roleList=[]} User{id=10, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=null, roleList=[]} User{id=11, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=null, roleList=[]} [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@49d904ec] [org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 1238959340 to pool. Process finished with exit code 0大家在开始学习mybatis插件的时候可以下载一个插件,可以通过这个插件就能像Spring查看方法的定义之处。
这算是第二遍学习mybatis了,还不错。过去学的东西忘了好多,但是学习过后,有的东西都加深了理解。以前很多不会的知识,现在懂了很多。要加油哦~接下来就要学习mybatis-plus,不知道这个难度如何。感觉这个应该和mybatis差距不大,毕竟是基于mybatis的。加油!!!
