Mybatis02
Mybatis学习的第二天,有Mybatis核心配置文件、测试的准备、Mybatis工具类的封装、易错点。
Mybatis学习02
1、Mybatis核心配置文件
-
XML 配置文件中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。
-
官方推荐XML配置文件命名为:mybatis-config.xml
XML文件放置的路径为:main/resources
<?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> //默认的环境id为“development” <environments default="development"> //一个环境的配置 <environment id="development"> //事务管理器类型为JDBC,还有一个MANAGED,但是几乎不用了 <transactionManager type="JDBC"/> //数据源为一个池子 <dataSource type="POOLED"> //连接数据库的各种配置 <property name="driver" value="driver"/> <property name="url" value="{url"/> <property name="username" value="username"/> <property name="password" value="password"/> </dataSource> </environment> </environments> </configuration>
2、测试的准备
-
Jave Bean
实体类的创建和之前的创建方式一样。
package com.neversettle.domain; public class User { private int id; private String username; private String birthday; private String sex; private String address; public User() { } public User(int id, String username, String birthday, String sex, String address) { this.id = id; this.username = username; this.birthday = birthday; this.sex = sex; this.address = address; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } 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 getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } 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 + '\'' + '}'; } }
-
实体类的持久化操作,也就是UserDao,但是Mybatis官方使用的是Mapper,所以此处命名为UserMapper(后期优化Mybatis也需要此种规范命名)
package com.neversettle.dao; import com.neversettle.domain.User; import java.util.List; public interface UserMapper { //获取全部用户信息 List<User> getUserList(); //根据ID获取用户信息 User getUserById(int id); //新增一个用户 void addUser(User user); //修改用户信息 int updateUser(User user); //删除一个用户 int deleteUser(int id); }
这里只需要写出其接口即可,具体的实现是在XML中执行的。
-
UserMapper的具体实现,需要在其UserMapper的同一目录下建一个名为 UserMapper.xml 文件,文件中写出其具体实现。
官方文档: 事实上 MyBatis 提供的全部特性都可以利用基于 XML 的映射语言来实现,这使得 MyBatis 在过去的数年间得以流行。
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="org.mybatis.example.BlogMapper"> <select id="selectBlog" resultType="Blog"> select * from Blog where id = #{id} </select> </mapper>
- mapper中有着CRUD的各个标签,相应的SQL语句都在对应的标签中书写。
- select等标签中id对应的是接口中的方法名,该标签就是接口中方法的具体实现。
- resultType是返回值类型,如返回的类型是具体的实体类,则写出具体的实体类,注意此时需要写出完整的地址,如之前的javabean中实体类的,则需写出实体类所在包名+实体类名,如com.neversettle.domain (后期可使用注解优化)
- 如果需要传参数,则需写出传入的参数类型,向SQL语句中插入时使用 #{} 花括号中写出参数,如果传入的参数是一个实体类,则可以直接写出实体类的属性。如User实体类中有id属性,则可直接写出 #{id} 。
而我实际的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"> <!--namespace绑定一个指定的Dao/Mapper接口--> <mapper namespace="com.neversettle.dao.UserMapper"> <!-- 查询语句--> <select id="getUserList" resultType="User"> select * from user </select> <!-- 根据ID查询用户--> <select id="getUserById" parameterType="int" resultType="User"> select * from user where id = #{id} </select> <!-- 新增加一个用户--> <insert id="addUser" parameterType="User"> insert into user values(#{id},#{username},#{birthday},#{sex},#{address}) </insert> <!-- 修改用户信息--> <update id="updateUser" parameterType="User"> update user set username = #{username} where id = #{id}; </update> <!-- 删除用户信息--> <delete id="deleteUser" parameterType="int"> delete from user where id = #{id} </delete> </mapper>
-
在Test中写测试代码
-
需要获得类似之前的connection的连接,在Mybatis中是SqlSession,而Mybatis中使用的是工厂模式(还未学习,暂且这样理解),SqlSession是从工厂中获取,而工厂就相当于一个池子,可以产生多个连接,官方给出的工厂获取代码如下:
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
而获取一个SqlSession的代码是:
SqlSession sqlSession = sqlSessionFactory.openSession();
接下来就可以来实现接口了,具体应该使用:
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
然后便可使用mapper来执行具体的方法,如:
User userById = mapper.getUserById(43);
-
而我的具体代码为(封装了Mybatis获取SqlSession的工具类):
package com.neversettle.dao; import com.neversettle.domain.User; import com.neversettle.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class UserMapperTest { @Test public void test(){ //1.获取SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //2.执行sql(第一种) UserMapper userDao = sqlSession.getMapper(UserMapper.class); List<User> userList = userDao.getUserList(); for (User user : userList) { System.out.println(user.toString()); } //3.关闭SqlSession sqlSession.close(); } @Test public void getUserById(){ //1.获取sqlsession SqlSession sqlSession = MybatisUtils.getSqlSession(); //2.执行sql UserMapper mapper = sqlSession.getMapper(UserMapper.class); User userById = mapper.getUserById(43); System.out.println(userById); //3.关闭 sqlSession.close(); } @Test public void addUser(){ //1.获取执行的sqlsession SqlSession sqlSession = MybatisUtils.getSqlSession(); //2.执行 UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User(50,"张三","2020-01-18","男","河北省石家庄市")); //3.关闭 sqlSession.commit(); sqlSession.close(); } @Test public void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(new User(50,"123","","","")); sqlSession.commit(); sqlSession.close(); } @Test public void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteUser(50); sqlSession.commit(); sqlSession.close(); } }
-
3、Mybaits工具类的封装
类似之前的JDBCUtils一样,Mybatis有些步骤也是重复的,所以可以封装成一个工具类:
package com.neversettle.utils;
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.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
//获取sqlsessionfactory对象
InputStream inputStream = null;
try {
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了。
// SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。
// 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
4、易错点
-
首先是UserMapper.xml,每一个mapper都需要在Mybatis的核心配置文件中注册,之前写核心配置文件时没有我们这次使用的Mapper,所以肯定会出现mapper未注册的错误,更改后的Mybatis的核心配置文件:
<?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"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=ture&characterEncoding=UTF-8&serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="newpassword"/> </dataSource> </environment> </environments> <!-- 每一个Mapper.xml都需要注册--> <mappers> <mapper resource="com/neversettle/dao/UserMapper.xml"/> </mappers> </configuration>
-
在执行增删改操作时,都需要提交事务,这和之前学习的不一样,之前学习的还需要自己开启事务然后再提交事务,这里貌似已经自动开启事务了,所以在执行完增删改操作后都需要提交事务,代码为:
sqlSession.commit();
-
第一次运行时,出现了 “ 1 字节的 UTF-8 序列的字节 1 无效” ,这是编码造成的问题,将IDEA的编码改为UTF-8,然后删掉 XML文件,再重写一个即可。