mybatis框架练习
mybatis框架中,包括实体类(这些实体类与数据库中的字段属性相对应),mybatis的配置文件(即mybatis-config.xml,这个配置文件用于连接实体类和orm(object relationship mapping 对象关系映射),以及做连接数据库的配置信息的配置),ORM(相当于xxxDao的实现类,同时将对象和数据库表的关系对应起来),xxxDao接口(用于外界使用时调用功能方法)
一对多关系查询
user对象----pet对象:一个人user可以有多只宠物 pet,而一个宠物只能有一个主人,因此他们是一对多的关系
user对象----hobby对象:一个人可以有多个爱好,一个爱好也可以有多个人同时拥有,因此他们是多对多的关系
area对象 上级对下级是一对多关系 采用 自连接 实现关系查询
user(
int userId
String userName
String gender
int score
list<pet> pets //在user对象中,设置一个list来存放宠物
list<hobby> hobbys
)
pet(
user user // 在pet对象中,设置一个user对象,表示该宠物的主人
int petId
String petName
)
hobby(
list<user> users
int hobbyId
String hobbyName
)
area(
int areaId
String areaName
int parentId
list<area> childAreaList
)
文档树建立
MyBatisUtils 类,用来读取mybatis的配置文件mybatis-config.xml
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
private static Reader reader;
static {
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
配置实体类和ORM的路径
<?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>
<!-- 1. 模型对象 -->
<typeAliases>
<!-- 定义实体类的地方 -->
<typeAlias alias="User" type="com.bwf.entity.User"/>
<typeAlias alias="Pet" type="com.bwf.entity.Pet"/>
<typeAlias alias="Hobby" type="com.bwf.entity.Hobby"/>
<typeAlias alias="Area" type="com.bwf.entity.Area"/>
<!-- <package name="com.bwf.entity"/>
这种方式就可以把entity包下的类都定义好,只是自动定义的别名是类名的小写形式-->
</typeAliases>
<!-- 2. 数据库连接信息 -->
<environments default="development">
<!-- 开发环境 -->
<environment id="development">
<!-- 事务管理器:基于jdbc -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--
jdbc参数:
user 用户名
password 密码
useUnicode 是否使用Unicode字符集
characterEncoding 当useUnicode为true是,指定字符编码(utf-8\gbk\gb2312)
autoReconnect 当数据库断开时,是否自动连接
autoReconnectForPools 是否使用针对数据库连接池的重连策略
failOverReadOnly 自动重连成功后,连接是否设置为只读?
maxReconnects autoReconnect设置为true时,重试连接的次数
initialTimeout autoReconnect设置为true时,两次重连之间的时间间隔,单位:秒
connectTimeout 和数据库服务器建立socket连接时的超时,单位:毫秒。 0表示永不超时,适用于JDK 1.4及更高版本
socketTimeout socket操作(读写)超时,单位:毫秒。 0表示永不超时
timeZone\serverTimezone 设置时区
useSSL 使用ssl协议
-->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis1?useUnicode=true&characterEncoding=utf-8&serverTimezone=PRC&useSSL=true" />
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<!--
生产环境
<environment id="production"></environment>
-->
</environments>
<!-- 3. ORM -->
<mappers>
<!-- 通过这个文件 把 数据库中的表 映射到 实体类上去 -->
<mapper resource="com/bwf/mapper/User.xml"/>
<mapper resource="com/bwf/mapper/Pet.xml"/>
<mapper resource="com/bwf/mapper/Hobby.xml"/>
<mapper resource="com/bwf/mapper/Area.xml"/>
</mappers>
</configuration>
UserDao
public interface UserDao {
//查询单个user
User getUserById(int id);
//增加
void add(User user);
//删除
void delete(int id);
//更新
void update(User user);
//查询所有元素
List<User> getUserList();
//查询指定性别的用户
List<User> getUserByGender(String gender);
//查询数据库表中的指定字段数据 ,需要在user.xml中配置resultMap
List<User> getNewUser();
//查询带有Pet集合的user列表
List<User> getUserListWithPet();
//查询带有Hobby集合的user列表
List<User> getUserListwithHobby();
}
ORM:user.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">
<!-- 对应 dao 中的 接口 相当于实现UserDao接口-->
<mapper namespace="com.bwf.dao.UserDao">
<!-- 这个配置文件相当于UserDao的实现类 -->
<!-- 自定义 返回数据类型 resultMap 这个东西在多表联查中使用较多-->
<!-- resultMap内放的是实体类的成员属性 -->
<!-- 如果数据库中的字段名与实体类中的属性名不同,则要配置下面的 映射 -->
<resultMap type="User" id="newUser">
<!-- 这里的type表示实体类 id表示经过映射得到的结果类
id="newUser"表示我们查询的结果可以用这个newUser来封装
在后面的查询配置中写返回值类型时就是用的id的值 -->
<!-- id标签表示主键字段 result标签表示其他字段 里面的column属性对应数据库中的字段名
property对应实体类中的属性名-->
<id column="user_id" property="userId"/>
<result column="username" property="username"/>
<result column="gender" property="gender"/>
<result column="score" property="score"/>
</resultMap>
<resultMap type="User" id="newUserwithPet">
<id column="user_id" property="userId"/>
<result column="username" property="username"/>
<result column="gender" property="gender"/>
<result column="score" property="score"/>
<!-- user对pet是一对多的关系 使用collection标签表示 -->
<!-- property 对应User中的List<Pet> pets集合 对应一方实体类中的 多方引用的属性
ofType 对应pets集合中元素的类型 对应查询结果集合中的元素类型
resultMap 相当于将Pet.xml中的resultMap加载进来 加载封装类newPet
也可以直接将Pet.xml中的resultMap复制过来 -->
<collection property="pets" ofType="Pet" resultMap="com.bwf.dao.PetDao.newPet" >
</collection>
</resultMap>
<resultMap type="User" id="newUserwithHobby">
<id column="user_id" property="userId"/>
<result column="username" property="username"/>
<result column="gender" property="gender"/>
<result column="score" property="score"/>
<!-- 打造包含Hobby集合的映射类 -->
<collection property="hobbies" ofType="Hobby" resultMap="com.bwf.dao.HobbyDao.newHobby"></collection>
</resultMap>
<!-- 对应 dao接口中的方法
id -> 方法名
parameterType -> 方法的形参类型
resultType -> 方法的返回值类型
-->
<!-- 添加模型对象 -->
<insert id="add" parameterType="User" keyProperty="user_id" useGeneratedKeys="true">
<!-- keyProperty="id"表示主键列为user.id,这个可有可无
useGeneratedKeys="true"表示插入数据时自增列自动增长 -->
<!-- insert into 'user' (username,gender,score) values (#{username},#{gender},#{score}); -->
insert into user values(null,#{username},#{gender},#{score})
</insert>
<!-- 删除模型对象 -->
<delete id="delete" parameterType="int">
delete from user where id = #{userId}
</delete>
<!-- 更新对象数据 -->
<update id="update" parameterType="User">
update `user` set username=#{username},gender=#{gender},score=#{score} where user_id=#{userId}
</update>
<!-- 查询对象数据
:::注意:::无论是查询单个还是多个对象,select标签中的返回值类型resultType 都必须设置成对应的实体类User -->
<!-- 根据Id查询一个模型对象 -->
<select id="getUserById" parameterType="int" resultMap="newUser">
select * from `user` where user_id = #{userId}
</select>
<!-- 查询用户列表 -->
<select id="getUserList" resultMap="newUser">
select * from `user`
</select>
<!-- 查询指定性别的user -->
<!-- 因为String不是基本数据类型,所以要带上包名 -->
<select id="getUserByGender" parameterType="java.lang.String" resultMap="newUser">
select * from `user` where gender=#{gender}
</select>
<!-- 查询数据库表中的指定字段数据 在这里就使用到了resultMap中的newUser-->
<select id="getNewUser" resultMap="newUser">
select user_id,username from `user`
<!-- 也可以这样 select * from `user` 只是待会mybatis封装时只封装这两个字段的数据 但是这种方法会将查询结果封装成User 不建议这样写 -->
<!-- 我觉得并不是这样,而是只要写一个简单类型(包括所有的简单数据类型属性)的resultMap,然后写一个查找指定字段的sql语句 -->
</select>
<!-- 查询带有Pet集合的user列表 -->
<select id="getUserListWithPet" resultMap="newUserwithPet">
select * from user left outer join pet on user.user_id = pet.user_id
</select>
<!-- 查询带有Hobby集合的user列表 -->
<select id="getUserListwithHobby" resultMap="newUserwithHobby">
select * from user u left join user_hobby uh on u.user_id = uh.user_id left join hobby h on uh.hobby_id = h.hobby_id
</select>
</mapper>
PetDao
public interface PetDao {
Pet getPetById(int petId);
List<Pet> getPetList();
List<Pet> getPetswithUser();
}
pet.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">
<!-- 对应 dao 中的 接口 -->
<mapper namespace="com.bwf.dao.PetDao">
<resultMap type="Pet" id="newPet">
<id column="pet_id" property="petId"/>
<result column="pet_name" property="petName"/>
</resultMap>
<resultMap type="Pet" id="newPetwithUser">
<id column="pet_id" property="petId"/>
<result column="pet_name" property="petName"/>
<!-- Pet对User是多对一关系 使用association(关联)标签
方法一与User.xml中的一样,引用过来
不同点事这里用的 javaType
-->
<association property="user" javaType="User" resultMap="com.bwf.dao.UserDao.newUser">
<!-- 一种方法是将User.xml中的resultMap内容拷过来 -->
</association>
</resultMap>
<!-- 查询对象数据 -->
<!-- 根据Id查询一个模型对象 -->
<select id="getPetById" parameterType="int" resultMap="newPet">
select * from `pet` where pet_id = #{petId}
</select>
<!-- 查询用户列表 -->
<select id="getPetList" resultMap="newPet">
select * from `pet`
</select>
<select id="getPetswithUser" resultMap="newPetwithUser">
select * from pet left outer join user on pet.user_id=user.user_id
</select>
</mapper>
HobbyDao
public interface HobbyDao {
//查询有同一爱好的所有用户和爱好的信息
List<Hobby> getHobbyListforUser();
}
hobby.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">
<mapper namespace="com.bwf.dao.HobbyDao">
<resultMap type="Hobby" id="newHobby">
<id column="hobby_id" property="hobbyId"/>
<result column="hobby_name" property="hobbyName"/>
</resultMap>
<resultMap type="Hobby" id="newHobbyforUser">
<id column="hobby_id" property="hobbyId"/>
<result column="hobby_name" property="hobbyName"/>
<collection property="users" ofType="User" resultMap="com.bwf.dao.UserDao.newUser">
</collection>
</resultMap>
<select id="getHobbyListforUser" resultMap="newHobbyforUser">
select * from hobby h left join user_hobby uh on h.hobby_id = uh.hobby_id left join user u on uh.user_id = u.user_id
</select>
</mapper>
AreaDao
public interface AreaDao {
Area getAreaById(int areaId);
List<Area> getAreaByName(String areaName);
//查询带下级的Area
Area getAreawithChild(int areaId);
List<Area> getChildAreaByParentId(int parentId);
//查询一个带上下级的Area
Area getAreawithParentandChild(int areaId);
}
area.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">
<mapper namespace="com.bwf.dao.AreaDao">
<resultMap type="Area" id="baseArea">
<id column="area_id" property="areaId"/>
<result column="area_name" property="areaName"/>
<result column="parent_id" property="parentId"/>
</resultMap>
<!-- 查询带子集的Area -->
<resultMap type="Area" id="areawithChild">
<id column="area_id" property="areaId"/>
<result column="area_name" property="areaName"/>
<result column="parent_id" property="parentId"/>
<!-- <collection property="childAreaList" ofType="Area" resultMap="baseArea"></collection>
这种方式查出的结果主表和从表的属性名会重复,我们不知道要如何进行封装,不可行-->
<!-- 上下级关系为 “自连接” 关系
要采用两次查询,即通过递归解决
column 表示主键列,我们要通过主键列来进行二次查询
select 引用另一个方法:我们传入一个编号,他帮我们查出所有子集,不包括自己
接下来在 Area 中添加一个 getChildAreaByParentId 方法
要实现递归操作,将 ofType 的值设置成 areawithChild 类型 这样查询结果就可以带 子集
如果写Area类型相当于用的是baseArea类型
-->
<collection property="childAreaList"
ofType="areawithChild"
column="area_id"
select="getChildAreaByParentId"
></collection>
</resultMap>
<select id="getAreaById" parameterType="int" resultMap="baseArea">
select * from area where area_id = #{areaId}
</select>
<select id="getAreawithChild" parameterType="int" resultMap="areawithChild">
select * from area where area_id = #{areaId}
</select>
<!-- 通过parentId查询本级的所有子集,不包括本级本身,由sql语句决定
这里的 resultMap 设置成 areawithChild 类型是为了递归查找子集,一直可以查询下去-->
<select id="getChildAreaByParentId" parameterType="int" resultMap="areawithChild">
select * from area where parent_id = #{parentId}
</select>
<!--
<select id="getAreawithParentandChild" parameterType="int" resultMap="">
</select> -->
</mapper>
测试数据mybatis.sql
/*
SQLyog Ultimate v8.32
MySQL - 5.5.20 : Database - mybatis1
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis1` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `mybatis1`;
/*Table structure for table `area` */
DROP TABLE IF EXISTS `area`;
CREATE TABLE `area` (
`area_id` int(11) NOT NULL,
`area_name` varchar(40) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`area_id`),
KEY `FK_CHINA_REFERENCE_CHINA` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
/*Data for the table `area` */
insert into `area`(`area_id`,`area_name`,`parent_id`) values (110000,'北京市',NULL),(110100,'东城区',110000),(110200,'西城区',110000),(110500,'朝阳区',110000),(110600,'丰台区',110000),(110700,'石景山区',110000),(110800,'海淀区',110000),(110900,'门头沟区',110000),(111100,'房山区',110000),(111200,'通州区',110000),(111300,'顺义区',110000),(111400,'昌平区',110000),(111500,'大兴区',110000),(111600,'怀柔区',110000),(111700,'平谷区',110000),(112800,'密云县',110000),(112900,'延庆县',110000),(120000,'天津市',NULL),(120100,'和平区',120000),(120200,'河东区',120000),(120300,'河西区',120000),(120400,'南开区',120000),(120500,'河北区',120000),(120600,'红桥区',120000),(120900,'滨海新区',120000),(121000,'东丽区',120000),(121100,'西青区',120000),(121200,'津南区',120000),(121300,'北辰区',120000),(121400,'武清区',120000),(121500,'宝坻区',120000),(122100,'宁河县',120000),(122300,'静海县',120000),(122500,'蓟县',120000),(130000,'河北省',NULL),(130100,'石家庄市',130000),(130101,'市辖区',130100),(130102,'长安区',130101),(130103,'桥东区',130101),(130104,'桥西区',130101),(130105,'新华区',130101),(130107,'井陉矿区',130101),(130108,'裕华区',130101),(130121,'井陉县',130100),(130123,'正定县',130100),(130124,'栾城县',130100),(130125,'行唐县',130100),(130126,'灵寿县',130100),(130127,'高邑县',130100),(130128,'深泽县',130100),(130129,'赞皇县',130100),(130130,'无极县',130100),(130131,'平山县',130100),(130132,'元氏县',130100),(130133,'赵县',130100),(130181,'辛集市',130100),(130182,'藁城市',130100),(130183,'晋州市',130100),(130184,'新乐市',130100),(130185,'鹿泉市',130100),(130200,'唐山市',130000),(130201,'市辖区',130200),(130202,'路南区',130201),(130203,'路北区',130201),(130204,'古冶区',130201),(130205,'开平区',130201),(130207,'丰南区',130201),(130208,'丰润区',130201),(130223,'滦县',130200),(130224,'滦南县',130200),(130225,'乐亭县',130200),(130227,'迁西县',130200),(130229,'玉田县',130200),(130230,'唐海县',130200),(130281,'遵化市',130200),(130283,'迁安市',130200),(130300,'秦皇岛市',130000),(130301,'海港区',130300),(130303,'山海关区',130300),(130304,'北戴河区',130300),(130321,'青龙满族自治县',130300),(130322,'昌黎县',130300),(130323,'抚宁县',130300),(130324,'卢龙县',130300),(130400,'邯郸市',130000),(130401,'市辖区',130400),(130402,'邯山区',130401),(130403,'丛台区',130401),(130404,'复兴区',130401),(130406,'峰峰矿区',130401),(130421,'邯郸县',130400),(130423,'临漳县',130400),(130424,'成安县',130400),(130425,'大名县',130400),(130426,'涉县',130400),(130427,'磁县',130400),(130428,'肥乡县',130400),(130429,'永年县',130400),(130430,'邱县',130400),(130431,'鸡泽县',130400),(130432,'广平县',130400),(130433,'馆陶县',130400),(130434,'魏县',130400),(130435,'曲周县',130400),(130481,'武安市',130400),(130500,'邢台市',130000),(130501,'市辖区',130500),(130502,'桥东区',130501),(130503,'桥西区',130501),(130521,'邢台县',130500),(130522,'临城县',130500),(130523,'内丘县',130500),(130524,'柏乡县',130500),(130525,'隆尧县',130500),(130526,'任县',130500),(130527,'南和县',130500),(130528,'宁晋县',130500),(130529,'巨鹿县',130529),(130530,'新河县',130500),(130531,'广宗县',130500),(130532,'平乡县',130500),(130533,'威县',130500),(130534,'清河县',130500),(130535,'临西县',130500),(130581,'南宫市',130500),(130582,'沙河市',130500),(130600,'保定市',130000),(130601,'新市区',130600),(130603,'北市区',130600),(130604,'南市区',130600),(130621,'满城县',130600),(130622,'清苑县',130600),(130623,'涞水县',130600),(130624,'阜平县',130600),(130625,'徐水县',130600),(130626,'定兴县',130600),(130627,'唐县',130600),(130628,'高阳县',130600),(130629,'容城县',130600),(130630,'涞源县',130600),(130631,'望都县',130600),(130632,'安新县',130600),(130633,'易县',130600),(130634,'曲阳县',130600),(130635,'蠡县',130600),(130636,'顺平县',130600),(130637,'博野县',130600),(130638,'雄县',130600),(130681,'涿州市',130600),(130682,'定州市',130600),(130683,'安国市',130600),(130684,'高碑店市',130600),(130685,'白沟新城县',130600),(130700,'张家口市',130000),(130701,'市辖区',130700),(130702,'桥东区',130701),(130703,'桥西区',130701),(130705,'宣化区',130701),(130706,'下花园区',130701),(130721,'宣化县',130700),(130722,'张北县',130700),(130723,'康保县',130700),(130724,'沽源县',130700),(130725,'尚义县',130700),(130726,'蔚县',130700),(130727,'阳原县',130700),(130728,'怀安县',130700),(130729,'万全县',130700),(130730,'怀来县',130700),(130731,'涿鹿县',130700),(130732,'赤城县',130700),(130733,'崇礼县',130700),(130800,'承德市',130000),(130801,'市辖区',130800),(130802,'双桥区',130801),(130803,'双滦区',130801),(130804,'鹰手营子矿区',130801),(130821,'承德县',130800),(130822,'兴隆县',130800),(130823,'平泉县',130800),(130824,'滦平县',130800),(130825,'隆化县',130800),(130826,'丰宁满族自治县',130800),(130827,'宽城满族自治县',130800),(130828,'围场满族蒙古族自治县',130800),(130900,'沧州市',130000),(130901,'市辖区',130900),(130902,'新华区',130901),(130903,'运河区',130901),(130921,'沧县',130900),(130922,'青县',130900),(130923,'东光县',130900),(130924,'海兴县',130900),(130925,'盐山县',130900),(130926,'肃宁县',130900),(130927,'南皮县',130900),(130928,'吴桥县',130900),(130929,'献县',130900),(130930,'孟村回族自治县',130900),(130981,'泊头市',130900),(130982,'任丘市',130900),(130983,'黄骅市',130900),(130984,'河间市',130900),(131000,'廊坊市',130000),(131001,'市辖区',131000),(131002,'安次区',131001),(131003,'广阳区',131001),(131022,'固安县',131000),(131023,'永清县',131000),(131024,'香河县',131000),(131025,'大城县',131000),(131026,'文安县',131000),(131028,'大厂回族自治县',131000),(131081,'霸州市',131000),(131082,'三河市',131000),(131100,'衡水市',130000),(131101,'市辖区',131100),(131102,'桃城区',131101),(131121,'枣强县',131100),(131122,'武邑县',131100),(131123,'武强县',131100),(131124,'饶阳县',131100),(131125,'安平县',131100),(131126,'故城县',131100),(131127,'景县',131100),(131128,'阜城县',131100),(131181,'冀州市',131100),(131182,'深州市',131100),(140000,'山西省',NULL),(140100,'太原市',140000),(140101,'市辖区',140100),(140105,'小店区',140101),(140106,'迎泽区',140101),(140107,'杏花岭区',140101),(140108,'尖草坪区',140101),(140109,'万柏林区',14010