不用导入骨架,pom.xml配置如下:
(这里我的数据库是8.0.18,mybatis是3.4.5,根据不同的版本可调整自己的配置)
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.sjhgroupId>
<artifactId>mybatisartifactId>
<packaging>jarpackaging>
<version>1.0-SNAPSHOTversion>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>8source>
<target>8target>
configuration>
plugin>
plugins>
build>
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.18version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.12version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
project>
这里我创建在test数据库中,根据自己的需要调整
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '用户名称',
`birthday` DATETIME DEFAULT NULL COMMENT '生日',
`sex` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`username`,`birthday`,`sex`,`address`)
VALUES (41,'老王','2018-02-27 17:47:08','男','北京'),
(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),
(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),
(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),
(46,'老王','2018-03-07 17:37:26','男','北京'),
(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');
用来封装查询数据库返回的结果
创建一个User类,并创建对应的setter/getter和toString方法,这里建议使用包装类型,因为当数据不存在时返回null值,但基本类型是不能接收的,会报错。
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
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 Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
public interface IUserDao {
//查询所有用户
List<User> findAll();
}
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="sjh2019"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="dao/IUserDao.xml" />
mappers>
configuration>
放在resources目录下,结构要和对应的接口目录结构一致
//namespace值为对应接口全限定类名
<mapper namespace="dao.IUserDao">
<select id="findAll" resultType="domain.User">
select * from user;
select>
mapper>
在test包中创建测试类
public class MybatisTest {
@Test
//查询所有用户
public void test() throws IOException {
//读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建sqlsession工厂对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//创建sqlsession对象
SqlSession sqlSession = factory.openSession();
//创建IUserDao代理类
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
//调用方法
List<User> users = userDao.findAll();
//打印结果
users.forEach(System.out::println);
//关闭资源
inputStream.close();
}
}
以上是使用xml的方式,接下来介绍使用注解的方式
首先删除掉映射配置文件(否则会报错,因为会优先使用xml配置),在主配置文件中,修改mappers属性
使用注解配置时,设置class的值为dao接口全限定类名
<mappers>
<mapper class="dao.IUserDao"/>
mappers>
接着在dao接口的方法上加上注解
public interface IUserDao {
//查询所有用户
@Select("select * from user")
List<User> findAll();
}
之后运行,可得到相同结果。
public class MybatisTest {
private InputStream inputStream;
private SqlSession sqlSession;
private IUserDao userDao;
@Before//在Test执行前执行
public void init() throws IOException {
//读取配置文件
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建sqlsession工厂对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//创建sqlsession对象
sqlSession = factory.openSession();
//创建IUserDao代理类
userDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destroy() throws IOException {
//提交事务
sqlSession.commit();
//关闭资源
inputStream.close();
}
@Test
//查询所有用户
public void test() throws IOException {
//调用方法
List<User> users = userDao.findAll();
//打印结果
users.forEach(System.out::println);
}
}
//保存用户
void saveUser(User user);
在映射配置wenj文件IUserDao.xml的mapper中加入
插入格式使用#{封装类的属性名}
,parameterType值是参数类的全限定类名
<insert id="saveUser" parameterType="domain.User">
insert into user(username,birthday,sex,address)
values (#{username},#{birthday},#{sex},#{address});
insert>
@Test
//保存用户
public void save(){
//创建要保存的用户对象
User user = new User();
user.setUsername("范闲");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("南庆");
//调用方法
userDao.saveUser(user);
}
//更新用户
void updateUser(User user);
<update id="updateUser" parameterType="domain.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id};
update>
@Test
//更新用户
public void update(){
//创建要更新的用户对象
User user = new User();
user.setId(49);
user.setUsername("司理理");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("北齐");
//调用方法
userDao.updateUser(user);
}
//删除用户
void deleteUser(Integer id);
当只有一个属性时,名称可任意,这里我任意起名randomid(实际即dao接口方法的参数id)
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{randomid};
delete>
@Test
//删除用户
public void delete(){
//调用方法
userDao.deleteUser(49);
}
//查询一个用户
User findById(Integer id);
//根据名字模糊查询
User findLike(String name);
<select id="findById" parameterType="INT" resultType="domain.User">
select * from user where id=#{uid};
select>
<select id="findLike" parameterType="string" resultType="domain.User">
select * from user where username like #{likename};
select>
模糊查询时也可以使用select * from user where username like '%${value}%;
,但该方法相当于拼接字符串,不安全,因此不推荐使用。
------------------------`
@Test
//查询一个用户
public void findbyid(){
//调用方法
User user = userDao.findById(48);
System.out.println(user);
}
@Test
//模糊查询用户
public void findlike(){
//调用方法
List<User> users = userDao.findLike("%王%");
users.forEach(System.out::println);
}
//查询记录总数
int count();
<select id="count" resultType="int">
select count(*) from user ;
select>
@Test
//查询记录数
public void count(){
//调用方法
int count = userDao.count();
System.out.println(count);
}
在之前的insert标签中加入selectKey标签。
keyProperty
:对应的实体类属性名
keyColumn
:对应的数据库列名
order
:执行顺序,after代表在insert语句执行后执行
<insert id="saveUser" parameterType="domain.User">
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address});
</insert>
@Test
//保存用户
public void save(){
//创建要保存的用户对象
User user = new User();
user.setUsername("范闲");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("南庆");
System.out.println("运行前"+user);
//调用方法
userDao.saveUser(user);
System.out.println("运行后"+user);
}
传递简单类型
传递pojo对象
Mybatis使用ognl表达式解析对象字段的值,#{}或者${}中的值为pojo属性名称
传递pojo包装对象
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。Pojo 类中包含 pojo。
案例:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
//根据Pojo包装类实现模糊查询
List<User> findByVo(QueryVo queryVo);
<select id="findByVo" parameterType="domain.QueryVo" resultType="domain.User">
select * from user where username like #{user.username};
select>
@Test
//模糊查询用户
public void findVo(){
QueryVo queryVo=new QueryVo();
User user=new User();
user.setUsername("%王%");
queryVo.setUser(user);
//调用方法
List<User> users = userDao.findByVo(queryVo);
users.forEach(System.out::println);
}
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。 在 select 标签中使用
resultMap
属性指定引用即可。
同时 resultMap 可以实现将查询结果映射为复杂类 型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
定义 resultMap
<resultMap type="domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
resultMap>
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名 property
属性:用于指定实体类属性名称
映射配置
<select id="findAll" resultMap="userMap">
select * from user
select>
测试结果
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
} }
例:
<select id="findAll" resultType="domain.User">
select id as userId,username as userName,birthday as userBirthday from user;
select>
之前的SqlMapConfig.xml
中property
标签配置的数据库信息可配置在properties
标签中,并使用${}
引用
也可配置外部文件,在resources
目录下创建一个jdbc.properties
resource 属性:用于指定 properties 配置文件的位置,要求配置文件必须在类路径下
使用该标签,可给实体类起别名,不需要在配置时再写全限定类名
<typeAliases>
<typeAlias type="domain.User" alias="user"/>
typeAliases>
type是实体类全限定类名,alias是别名,使用后不区分大小写
可直接使用别名
也是用来起别名的,该值指定一个包,该包中的所有类自动设置别名为类名/接口名,且不区分大小写
在IUserDao.xml配置中,不用再写全限定类名
具体结构如下:
相应地,MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource,
PooledDataSource 类来表示 UNPOOLED、POOLED 类型的数据源
在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术)。
我们的数据源配置就是在 SqlMapConfig.xml 文件中,具体配置如下:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
MyBatis 在初始化时,根据
的type
属性来创建相应类型的的数据源 DataSource,即:
type="POOLED"
:MyBatis 会创建 PooledDataSource 实例
type="UNPOOLED"
: MyBatis 会创建 UnpooledDataSource 实例
type="JNDI"
:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
事务控制
setAutoCommit()
方法就可以调整。setAutoCommit()
方法来设置事务提交方式的。