MyBatis简介
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
介绍接不多说了,下面开始写代码
准备事项
开发工具:IDEA, Idea中需要安装插件MyBatis plugin来支持开发MyBatis,这个插件非常的有用,安装和具体的作用,大家百度哈,这里只将mybatis
新建工程
在idea中新建一个简单的java工程,创建成功后的目录如下:
然后准备mybatis的包和连接数据库所用的包
mybatis的包,大家可以去http://github.com/mybatis/mybatis-3/releases下载,还有一个大家需要到网上下载,我把这两个包上传到CSDN上了,大家可以去下CSDN地址,百度云地址,提取码dbjv
在工程下面新建一个lib目录,将这个两个包放在lib目录下面
这里还没有结束,还要在项目中显示报这两个包导入到依赖中去,点击file ->project structure->Modules->Dependecies,然后点击+号,选择第一个
创建数据库和表
在创建实体类前,我们先创建表,创建一个test数据库,再创建一个user表,并插入两行数据
DROP DATABASE IF EXISTS test;
CREATE DATABASE test DEFAULT CHARACTER SET utf8;
use test;
CREATE TABLE user(
id int(11) NOT NULL AUTO_INCREMENT,
user_name varchar(255) NOT NULL,
password varchar(255) NOT NULL,
age int(11) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO user VALUES(1,'guolin','123456',18);
INSERT INTO user VALUES(2,'love','123456',18);
创建实体类
在src下创建一个dto的包,并dto包下创建一个User的实体类
package dto;
public class User {
private Integer id;
private String userName;
private String password;
private Integer age;
/*setter and getter*/
}
然后在src下面创建一个resources的包,并将其设置项目resources模块,具体操作,单击file -> project structure -> Modules:当resources文件夹右下角出现一个黄色小图标时就ok
将resources包设置成项目的resources模块后,接下来的我们的配置文件,以及实体类对应的xml文件都放在它下面
创建配置文件mybatis.xml
在resources下面新建一个mybatis的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>
<!-- 驼峰转换 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<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/test"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
</configuration>
配置User.xml
resources下新建一个mapper文件,然后在mapper下新建一个User.xml,项目中与实体类映射的xml我们都放到mapper下
<?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="dto">
<select id="listUser" resultType="dto.User">
select * from user;
</select>
</mapper>
这里namespace为dto,我们这里还没有使用接口绑定,所以指向的是我们的实体类的包,这里引用一下官网的解释
然后我们写了一个select语句,id为listUser,resultType表示返回类型,我们这里是User类型,然后我们要到mybatis中配置一下,这样mybatis才能找到我们user.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>
<!-- 驼峰转换 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<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/test"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="mapper/User.xml"/>
</mappers>
</configuration>
测试类
在src下新建一个test包,在包下新建一个Test类
package test;
import dto.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.InputStream;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
// 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent
List<User> listStudent = session.selectList("listUser");
for (User user : listStudent) {
System.out.println("ID:" + user.getId() + ",NAME:" + user.getUserName());
}
}
}
运行结果
增删改查
在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">
<mapper namespace="dto">
<select id="listUser" resultType="dto.User">
select * from user;
</select>
<insert id="addUser" parameterType="dto.User">
insert into user (id, user_name,password,age)
values(#{id},#{userName},#{password},#{age})
</insert>
<delete id="deleteUser" parameterType="dto.User">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="dto.User">
update user set user_name = #{userName},password = #{password} where id = #{id}
</update>
<select id="selectUserById" parameterType="java.lang.Integer" resultType="dto.User">
select * from user where id = #{id}
</select>
</mapper>
测试类
package test;
import dto.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.InputStream;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
//增加语句
User user1 = new User();
user1.setId(3);
user1.setUserName("xuchao");
user1.setPassword("123456");
user1.setAge(18);
session.insert("addUser",user1);
//删除语句
User user2 = new User();
user1.setId(1);
session.delete("deleteUser",user2);
//根据id查询单个user信息
User user3 = session.selectOne("selectUserById",2);
//更新语句
user3.setUserName("chenzixin");
user3.setPassword("1997");
session.update("updateUser",user3);
// 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent
List<User> listStudent = session.selectList("listUser");
for (User user : listStudent) {
System.out.println("ID:" + user.getId() + ",NAME:" + user.getUserName() + ",PASSWOED:" + user.getPassword());
}
session.commit(); //提交修改
session.close(); //关闭
}
}
新增一个id为3的user,然后删除id为1的用户,根据id查询为2的用户,最后修改用户2的信息,运行结果如下:
MyBatis高级映射
一对一查询,首先我们将user的数据全部删除,然后再将创建一张card表,并重新在user表中插入两条数据,card表也插入两条数据
use test;
create table card(
id int(11) NOT NULL auto_increment,
id_card int(11) NOT NULL,
primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO user VALUES(1,'guolin','123456',18);
INSERT INTO user VALUES(2,'chenzixin','123456',18);
INSERT INTO card VALUES(1,1996);
INSERT INTO card VALUES(2,1997);
这里的user中的id与card中id是对应的,没有再设置外键,下面来看一下我们的sql语句
使用resultType
mybatis有两种属性来表示返回类型resultType和resultMap,我们先来看第一种
resultType返回期望类型的类的完全限定名或别名,我们要新建一个java实体类来映射我们上述的一对一的结果
在dto包下面新建一个OneToOne类
package dto;
public class OneToOne {
private Integer id;
private String userName;
private String password;
private Integer age;
private Integer idCard;
/* setter and getter */
}
在上面的User.xml中增加如下的<select>类型的查询语句
<select id="findByIdCard" parameterType="java.lang.Integer" resultType="dto.OneToOne">
select
user.*,
card.*
from
user,card
where user.id = card.id and card.id_card = #{v};
</select>
测试类
package test;
import dto.OneToOne;
import dto.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.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
OneToOne one = session.selectOne("findByIdCard",1997);
System.out.println(one);
session.commit(); //提交修改
session.close(); //关闭
}
}
运行结果
上面打印使用log4j打印出了sql,大家可以配置一下,首先在lib目录下导入log4j-1.2.17.jar(这里是我使用的版本号,大家也可以使用别的版本)的包,然后在src新建log4j.properties配置文件,并输入一下内容:
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
#show sql
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
使用resultMap
先来创建card表的实体类,dto包中新建Card类
package dto;
public class Card {
private Integer id;
private Integer idCard;
private User user; //引入一个User对象
/* seeter and getter */
}
然后我们再新建一个Card.xml,同样是放在mapper目录下,使用resultMap来实现上诉例子
<?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="dto">
<resultMap id="resultByCard" type="dto.Card">
<id property="id" column="id"/>
<result property="idCard" column="id_card"/>
<association property="user" javaType="dto.User">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="password" column="password"/>
<result property="age" column="age"/>
</association>
</resultMap>
<select id="selectByCard" parameterType="java.lang.Integer" resultMap="resultByCard">
select
user.*,
card.*
from
user,card
where user.id = card.id and card.id_card = #{v};
</select>
</mapper>
这里需要在mybatis.xml中配置一下,不然mybatis就无法找到我们这些映射的文件
<!-- 映射文件 -->
<mappers>
<mapper resource="mapper/User.xml"/>
<mapper resource="mapper/Card.xml"/>
</mappers>
测试类
package test;
import dto.Card;
import dto.OneToOne;
import dto.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.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
Card one = session.selectOne("selectByCard",1997);
System.out.println(one);
session.commit(); //提交修改
session.close(); //关闭
}
}
运行结果
这里查询一个idCard为1997的用户信息,如何想的上面这个输出值,Card和User类需要添加toString()方法,否者你得到只会是类在jvm中的地址串
一对多映射
下面我们来看看一对多映射,这里我们再重新建两张表,class表和student表,在class表中只插入条数据,student中插入两条
use test;
CREATE TABLE class(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE student(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
class_id int(11) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO class VALUES(1,'一班');
INSERT INTO student VALUES(1,'guolin',1);
INSERT INTO student VALUES(2,'chenzixin',1)
然后来看一下我们这次的sql语句
实体类
创建实体类Class1和Student,还是位于dto包下,因为Class是java中的关键字,所以我们用Class1
package dto;
import java.util.List;
public class Class1 {
private Integer id;
private String name;
List<Student> list;
/* setter and getter */
}
package dto;
public class Student {
private Integer id;
private String name;
private Integer classId;
/* setter and getter */
}
上面Class1中引用了一个包含Student对象的list对象,表明一个班中包含哪些学生,下面创建Class1.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="dto">
<resultMap id="resultByClass1" type="dto.Class1">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="list" ofType="dto.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="classId" column="class_id"/>
</collection>
</resultMap>
<select id="selectByClass1" parameterType="java.lang.Integer" resultMap="resultByClass1">
select
class.*,
student.*
from
class,student
where class.id = student.class_id and class.id= #{parameter};
</select>
</mapper>
测试类
package test;
import dto.*;
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.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception{
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
Class1 one = session.selectOne("selectByClass1",1);
System.out.println(one);
session.commit(); //提交修改
session.close(); //关闭
}
}
运行结果
这里的结果有问题,list中应该有两条数据,Total也打印的是2,证明应该有两条,还有就是list中的name应该是student的名字,这里看上去被class的name覆盖了。百度后发现原因是由于class中的name属性覆盖了student中的name属性,至于为什么明明查出来两条数据,最后只打印一条的原因是因为class表和student表的id相同导致。
下面我们来修改,修改Class1.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="dto">
<resultMap id="resultByClass1" type="dto.Class1">
<id property="id" column="c_id"/>
<result property="name" column="s_name"/>
<collection property="list" ofType="dto.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
<result property="classId" column="class_id"/>
</collection>
</resultMap>
<select id="selectByClass1" parameterType="java.lang.Integer" resultMap="resultByClass1">
select
c.id as c_id,
c.name as c_name,
s.id as s_id,
s.name as s_name,
s.class_id
from
class c,student s
where c.id = s.class_id and c.id= 1;
</select>
</mapper>
这里我们为class和student分别取了别分,其中id和那么字段也取了别名,同时resultMap中的column也要相应修改
测试类不改,再次运行
结果正确,list中两条数据,并且name属性也没有被覆盖