一、MyBatis架构与项目搭建
● 导入Jar
数据库驱动包:mysql-connector-java-5.1.46-bin.jar
mybatis核心包:mybatis-3.4.6.jar
mybatis依赖:
● 准备数据库
● db.properties - mysql驱动配置文件(这样可以优化性能)
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/games_db?useUnicode=true&characterEncoding=UTF-8&useSSL=true jdbc.username=root jdbc.password=123456
● 引入log4j.properties文件(测试输出需要)
● 添加mybatis映射配置文件 - sqlMapConfig.xml
配置文件中主要是配置连接数据库和事务管理的内容,文件名可以自定义,默认SqlMapConfig.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> <!-- 引入外部配置文件 --> <properties resource="db.properties"></properties> <!-- 配置别名;推荐使用package包形式来配置别名;包的形式会扫描主包及子包中所有文件;以对象类名为别名,大小写不限,推荐使用小写 --> <typeAliases> <!-- <typeAlias type="com.sikiedu.beans.User" alias="user" /> --> <package name="com.sikiedu.beans" /> </typeAliases> <!-- 配置mybatis运行环境 ; 在集成Spring是不用 --> <environments default="development"> <environment id="development"> <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 --> <transactionManager type="JDBC" /> <!-- 使用连接池连接数据库 - mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI --> <!-- POOLED 表示支持JDBC数据源连接池 ; UNPOOLED 表示不支持数据源连接池 ; JNDI 表示支持外部数据源连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!--配置映射器的位置 --> <mappers> <!-- 单个配置 --> <!-- <mapper resource="com/sikiedu/mapper/UserMapper.xml" /> --> <!-- <mapper url="file:\D:JavaWorkSpaceJavaEE_SSM_Testssm_mybatissrccomsikiedumapperUserMapper.xml" /> --> <!-- <mapper class="com.sikiedu.mapper.UserMapper" /> --> <!-- 多配置-以包的形式;推荐使用 --> <package name="com.sikiedu.mapper" /> </mappers> </configuration>
● 创建数据库对应的实体对象
数据库实体对象
1 package com.sikiedu.beans; 2 3 public class Role { 4 5 private Integer id; 6 private String name; 7 private Integer level; 8 private String roletype; 9 private Integer userid; 10 11 public Integer getId() { 12 return id; 13 } 14 15 public void setId(Integer id) { 16 this.id = id; 17 } 18 19 public String getName() { 20 return name; 21 } 22 23 public void setName(String name) { 24 this.name = name; 25 } 26 27 public Integer getLevel() { 28 return level; 29 } 30 31 public void setLevel(Integer level) { 32 this.level = level; 33 } 34 35 public String getRoletype() { 36 return roletype; 37 } 38 39 public void setRoletype(String roletype) { 40 this.roletype = roletype; 41 } 42 43 public Integer getUserid() { 44 return userid; 45 } 46 47 public void setUserid(Integer userid) { 48 this.userid = userid; 49 } 50 51 @Override 52 public String toString() { 53 return "Role [id=" + id + ", name=" + name + ", level=" + level + ", roletype=" + roletype + ", userid=" 54 + userid + "]"; 55 } 56 57 }
1 package com.sikiedu.beans; 2 3 import java.util.Date; 4 5 public class User { 6 7 private Integer id; 8 private String username; 9 private String userpassword; 10 private Float balance; 11 private String grgisterdate; 12 13 public Integer getId() { 14 return id; 15 } 16 17 public void setId(Integer id) { 18 this.id = id; 19 } 20 21 public String getUsername() { 22 return username; 23 } 24 25 public void setUsername(String username) { 26 this.username = username; 27 } 28 29 public String getUserpassword() { 30 return userpassword; 31 } 32 33 public void setUserpassword(String userpassword) { 34 this.userpassword = userpassword; 35 } 36 37 public Float getBalance() { 38 return balance; 39 } 40 41 public void setBalance(Float balance) { 42 this.balance = balance; 43 } 44 45 public String getGrgisterdate() { 46 return grgisterdate; 47 } 48 49 public void setGrgisterdate(String grgisterdate) { 50 this.grgisterdate = grgisterdate; 51 } 52 53 @Override 54 public String toString() { 55 return "User [id=" + id + ", username=" + username + ", userpassword=" + userpassword + ", balance=" + balance 56 + ", grgisterdate=" + grgisterdate + "]"; 57 } 58 59 }
Vo为关联查询需要 - 一对一、一对多
1 package com.sikiedu.beans; 2 3 import java.util.List; 4 5 public class RoleVo extends Role { 6 7 private User user; 8 private List<Integer> idList; 9 10 public User getUser() { 11 return user; 12 } 13 14 public void setUser(User user) { 15 this.user = user; 16 } 17 18 public List<Integer> getList() { 19 return idList; 20 } 21 22 public void setList(List<Integer> idList) { 23 this.idList = idList; 24 } 25 26 @Override 27 public String toString() { 28 return "RoleVo [ID=" + getId() + " name=" + getName() + " roletype=" + getRoletype() + " user=" + user 29 + "]"; 30 } 31 32 }
1 package com.sikiedu.beans; 2 3 import java.util.List; 4 5 public class UserVo extends User { 6 // 维护一个Role集合 7 private List<Role> roleList; 8 9 public List<Role> getRole() { 10 return roleList; 11 } 12 13 public void setRole(List<Role> roleList) { 14 this.roleList = roleList; 15 } 16 17 @Override 18 public String toString() { 19 return "UserVo [ID=" + getId() + " username=" + getUsername() + " Grgisterdate=" + getGrgisterdate() 20 + " role=" + roleList + "]"; 21 } 22 23 }
● 创建方法接口XxxxMapper.java And 定义操作数据表的sql映射文件XxxMapper.xml
创建方法接口 - 提供简单的增删改查数据信息。
1 package com.sikiedu.mapper; 2 3 import java.util.List; 4 5 import com.sikiedu.beans.Role; 6 import com.sikiedu.beans.RoleVo; 7 8 public interface RoleMapper { 9 10 // 查询所有 11 public List<Role> selectAllRole(); 12 13 // 通过RoleVo一对一关联查询 14 public List<RoleVo> selectAllRoleVo(); 15 16 // 多条件查询 通过角色对象中的条件查询角色表 17 public List<Role> selectRoleListByRole(Role role); 18 19 // 多条件查询 通过角色对象中的条件查询角色表Trim 20 public List<Role> selectRoleListByTrim(Role role); 21 22 // 更新角色表 23 public void updateSetRole(Role role); 24 25 // 使用多个ID获取角色列表 By array 26 public List<Role> selectRoleListByids(Integer[] ids); 27 28 // 使用多个ID获取角色列表 By list 29 public List<Role> selectRoleListByList(List<Integer> idList); 30 31 // 使用多个ID获取角色列表 By RoleVo 32 public List<Role> selectRoleListByRoleVo(RoleVo roleVo); 33 34 }
1 package com.sikiedu.mapper; 2 3 import java.util.List; 4 5 import com.sikiedu.beans.User; 6 import com.sikiedu.beans.UserVo; 7 8 public interface UserMapper { 9 10 // 根据ID查询用户 11 public User selectUserById(Integer id); 12 13 // 根据用户名模糊查询用户 14 public List<User> selectUserLikeUsername(String username); 15 16 // 同过包装类UserVo查询用户 17 public User selectUserByUserVoId(UserVo vo); 18 19 // 查询用户总条数 20 public Integer selectUserCount(); 21 22 // 查询所有用户包装类 23 public List<UserVo> selectAllUserVo(); 24 }
定义操作数据表的sql映射文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.sikiedu.mapper.RoleMapper"> 6 7 <sql id="myselect"> 8 SELECT * 9 FROM role 10 </sql> 11 12 <resultMap type="Role" id="roleRM"> 13 <id property="id" column="idrole" /> 14 </resultMap> 15 <select id="selectAllRole" resultMap="roleRM"> 16 <include refid="myselect"></include> 17 </select> 18 19 <resultMap type="RoleVo" id="roleVo"> 20 <id property="id" column="idrole" /> 21 <result property="name" column="name" /> 22 <result property="level" column="level" /> 23 <result property="roletype" column="roletype" /> 24 <!-- 一对一关系 --> 25 <association property="user" javaType="User"> 26 <id property="id" column="id" /> 27 <result property="username" column="username" /> 28 </association> 29 </resultMap> 30 <!-- 一对一关联查询 --> 31 <select id="selectAllRoleVo" resultMap="roleVo"> 32 SELECT 33 r.idrole, 34 r.name, 35 r.level, 36 r.roletype, 37 u.id, 38 u.username 39 FROM role r 40 LEFT JOIN user u 41 ON r.idrole = u.id 42 </select> 43 44 <!-- 多条件查询 通过角色对象中的条件查询角色表 --> 45 <select id="selectRoleListByRole" parameterType="Role" resultMap="roleRM"> 46 <include refid="myselect"></include> 47 <where> 48 <if test="level!=null and level!=''"> 49 level = #{level} 50 </if> 51 <if test="roletype!=null and roletype!=''"> 52 AND roletype = #{roletype} 53 </if> 54 <if test="userid!=null"> 55 AND userid = #{userid} 56 </if> 57 </where> 58 </select> 59 60 <!--多条件查询 通过角色对象中的条件查询角色表Trim --> 61 <select id="selectRoleListByTrim" parameterType="Role" resultMap="roleRM"> 62 <include refid="myselect"></include> 63 <trim prefix="WHERE" suffixOverrides="AND"> 64 <if test="level!=null and level!=''"> 65 level = #{level} AND 66 </if> 67 <if test="roletype!=null and roletype!=''"> 68 roletype = #{roletype} AND 69 </if> 70 <if test="userid!=null"> 71 userid = #{userid} 72 </if> 73 </trim> 74 </select> 75 76 <!-- 更新角色表 --> 77 <update id="updateSetRole" parameterType="Role"> 78 UPDATE role 79 <set> 80 <if test="name != null and name != ''"> 81 name = '${name}', 82 </if> 83 <if test="level != null"> 84 level = ${level}, 85 </if> 86 <if test="roletype != null and roletype != ''"> 87 roletype = '${roletype}', 88 </if> 89 <if test="userid != null"> 90 userid = ${userid} 91 </if> 92 </set> 93 WHERE 94 idrole = #{id} 95 </update> 96 97 <!-- 使用多个ID获取角色列表 foreach遍历数组 --> 98 <select id="selectRoleListByids" resultMap="roleRM"> 99 <include refid="myselect"></include> 100 WHERE idrole IN 101 <foreach collection="array" item="id" open="(" separator="," close=")"> 102 ${id} 103 </foreach> 104 </select> 105 106 <!-- 使用多个ID获取角色列表 foreach遍历集合 --> 107 <select id="selectRoleListByList" resultMap="roleRM"> 108 <include refid="myselect"></include> 109 WHERE idrole IN 110 <foreach collection="list" item="id" open="(" separator="," close=")"> 111 ${id} 112 </foreach> 113 </select> 114 115 <select id="selectRoleListByRoleVo" resultMap="roleRM"> 116 <include refid="myselect"></include> 117 WHERE idrole IN 118 <foreach collection="list" item="id" open="(" separator="," close=")"> 119 ${id} 120 </foreach> 121 </select> 122 123 </mapper>
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.sikiedu.mapper.UserMapper"> 6 7 <!-- 查询用户 --> 8 <select id="selectUserById" parameterType="Integer" resultType="com.sikiedu.beans.User"> 9 SELECT * FROM user WHERE id = #{id} 10 </select> 11 <!-- #{}占位符 尽量选用#{}来解决问题 --> 12 <!-- ${}字符拼接 or1=1 容易被SQL注入 --> 13 <select id="selectUserLikeUsername" parameterType="String" resultType="User"> 14 <!-- SELECT * FROM coke.user WHERE username LIKE '%${value}%' --> 15 SELECT * FROM user WHERE username LIKE "%"#{username}"%" 16 </select> 17 18 <!-- 添加用户 --> 19 <insert id="insertUser" parameterType="com.sikiedu.beans.User"> 20 INSERT INTO user VALUES(null,#{username},#{userpassword},#{balance},#{grgisterdate}) 21 </insert> 22 23 <!-- 修改用户 --> 24 <update id="updateUser" parameterType="com.sikiedu.beans.User"> 25 UPDATE user SET username = #{username} WHERE id = #{id} 26 </update> 27 28 <!-- 删除用户 --> 29 <delete id="deleteUserById" parameterType="Integer"> 30 DELETE FROM user WHERE id = #{id} 31 </delete> 32 33 <!-- 同过包装类UserVo查询用户 --> 34 <select id="selectUserByUserVoId" parameterType="UserVo" resultType="user"> 35 SELECT * FROM user WHERE id = #{id} 36 </select> 37 38 <!-- selectUserCount --> 39 <select id="selectUserCount" resultType="Integer"> 40 SELECT COUNT(*) FROM user 41 </select> 42 43 <resultMap type="UserVo" id="userVo"> 44 <id property="id" column="id" /> 45 <result property="username" column="username" /> 46 <result property="grgisterdate" column="grgisterdate" /> 47 <!-- 一对多关系 --> 48 <collection property="roleList" ofType="Role"> 49 <id property="id" column="idrole" /> 50 <result property="name" column="name" /> 51 <result property="roletype" column="roletype" /> 52 </collection> 53 </resultMap> 54 <!-- 一对多关联查询 --> 55 <select id="selectAllUserVo" resultMap="userVo"> 56 SELECT 57 u.id, 58 u.username, 59 u.grgisterdate, 60 r.idrole, 61 r.name, 62 r.roletype 63 FROM user u 64 LEFT JOIN role r 65 ON u.id = r.userid 66 </select> 67 68 </mapper>
映射配置文件里注册映射文件
1 <!--配置映射器的位置 --> 2 <mappers> 3 <!-- 单个配置 --> 4 <!-- <mapper resource="com/sikiedu/mapper/UserMapper.xml" /> --> 5 <!-- <mapper url="file:\D:JavaWorkSpaceJavaEE_SSM_Testssm_mybatissrccomsikiedumapperUserMapper.xml" /> --> 6 <!-- <mapper class="com.sikiedu.mapper.UserMapper" /> --> 7 <!-- 自动扫描包内的Mapper接口与配置文件 - 以包的形式;推荐使用 --> 8 <package name="com.sikiedu.mapper" /> 9 </mappers>
● Dao原始开发方式
原始dao开发思路比较简单,写个dao接口和dao实现类即可。
需要向dao实现类中注入sqlSessionFactory,在方法体内通过sqlSessionFactory创建sqlSession。操作完成之后,关闭资源。
为什么在方法体内创建呢?
因为mybatis中sqlSession是线程不安全的。如果在方法外面以成员变量的方式创建,可能会引发线程安全问题。
① dao层接口
1 package com.sikiedu.dao; 2 3 import java.util.List; 4 5 import com.sikiedu.beans.User; 6 import com.sikiedu.beans.UserVo; 7 8 public interface UserDao { 9 10 // 根据ID查询用户 11 public User selectUserById(Integer id); 12 13 // 根据用户名模糊查询用户 14 public List<User> selectUserLikeUsername(String username); 15 16 // 同过包装类UserVo查询用户 17 public User selectUserByUserVoId(UserVo vo); 18 19 // 查询用户总条数 20 public Integer selectUserCount(); 21 22 // 查询所有用户包装类 23 public List<UserVo> selectAllUserVo(); 24 25 }
② dao层接口实现类
1 package com.sikiedu.dao; 2 3 import java.util.List; 4 5 import org.apache.ibatis.session.SqlSession; 6 import org.apache.ibatis.session.SqlSessionFactory; 7 8 import com.sikiedu.beans.User; 9 import com.sikiedu.beans.UserVo; 10 11 public class UserDaoImpl implements UserDao { 12 13 // SQLSession工厂 14 private SqlSessionFactory ssf; 15 16 // 通过构造给ssf赋值 17 public UserDaoImpl(SqlSessionFactory ssf) { 18 super(); 19 this.ssf = ssf; 20 } 21 22 @Override 23 public User selectUserById(Integer id) { 24 25 // 生产一个session 26 SqlSession sqlSession = ssf.openSession(); 27 // 操作数据库 28 return sqlSession.selectOne("selectUserById", id); 29 } 30 31 @Override 32 public List<User> selectUserLikeUsername(String username) { 33 SqlSession sqlSession = ssf.openSession(); 34 return sqlSession.selectList("selectUserLikeUsername", username); 35 } 36 37 @Override 38 public User selectUserByUserVoId(UserVo vo) { 39 SqlSession sqlSession = ssf.openSession(); 40 return sqlSession.selectOne("selectUserByUserVoId", vo); 41 } 42 43 @Override 44 public Integer selectUserCount() { 45 SqlSession sqlSession = ssf.openSession(); 46 return sqlSession.selectOne("selectUserCount"); 47 } 48 49 @Override 50 public List<UserVo> selectAllUserVo() { 51 SqlSession sqlSession = ssf.openSession(); 52 return sqlSession.selectList("selectAllUserVo"); 53 } 54 55 }
③ JUnit的测试类
1 package com.sikiedu.test; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.util.List; 6 7 import org.apache.ibatis.io.Resources; 8 import org.apache.ibatis.session.SqlSessionFactory; 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 import org.junit.Test; 11 12 import com.sikiedu.beans.User; 13 import com.sikiedu.beans.UserVo; 14 import com.sikiedu.dao.UserDaoImpl; 15 16 public class UserDaoTest { 17 18 // sqlSession工厂 19 private static SqlSessionFactory ssf; 20 21 static { 22 String resource = "sqlMapConfig.xml"; 23 try { 24 // 读取配置文件 25 InputStream inputStream = Resources.getResourceAsStream(resource); 26 // 创建sqlSession工厂 27 ssf = new SqlSessionFactoryBuilder().build(inputStream); 28 } catch (IOException e) { 29 e.printStackTrace(); 30 } 31 } 32 33 @Test // 根据ID查询用户 34 public void test1() { 35 36 UserDaoImpl dao = new UserDaoImpl(ssf); 37 User user = dao.selectUserById(1); 38 System.out.println(user); 39 } 40 41 @Test // 同过包装类UserVo查询用户 42 public void test2() { 43 44 UserDaoImpl dao = new UserDaoImpl(ssf); 45 List<User> list = dao.selectUserLikeUsername(""); 46 for (User user : list) { 47 System.out.println(user); 48 } 49 } 50 51 @Test // 查询用户总条数 52 public void test3() { 53 54 UserDaoImpl dao = new UserDaoImpl(ssf); 55 Integer count = dao.selectUserCount(); 56 System.out.println(count); 57 } 58 59 @Test // 查询所有用户包装类 60 public void test4() { 61 62 UserDaoImpl dao = new UserDaoImpl(ssf); 63 List<UserVo> list = dao.selectAllUserVo(); 64 for (UserVo vo : list) { 65 System.out.println(vo); 66 } 67 } 68 }
● 原始Dao开发存在的问题
1、dao接口实现类方法中存在大量重复代码,从设计上来看,应该抽取。
2、调用sqlSession方法时,将satement的id硬编码了,即类似于”test.findUserById”这种,都写死了。
3、sqlSession的方法中,要求传入的参数是Object类型的(泛型),也就是说如果我传错了参数,编译不会报错,执行的时候才会报错,不利于开发。
Mapper接口开发方式是基于入门程序的基础上,对 控制程序 进行分层开发,程序员只需要 编写mapper接口 和 Mappe.xml 配置文件即可。
程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。
二、SqlSession的使用范围
● SqlSessionFactoryBuilder
通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory
将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。
在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。
● SqlSessionFactory
通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。
将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory。
● SqlSession
SqlSession是一个面向用户(程序员)的接口。
SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)、。
SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。
SqlSession最佳应用场合在方法体内,定义成局部变量使用。
三、增删改查操作
读取配置文件,创建sqlSessionFactory,获取sqlSession
// 读取配置文件 String resource = "sqlMapConfig.xml"; InputStream in = Resources.getResourceAsStream(resource); // 需要sqlSessionFactoryBuilder SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder(); // 创建sqlSessionFactory SqlSessionFactory ssf = ssfb.build(in); // 生产一个sqlSession SqlSession sqlSession = ssf.openSession();
♦ 增
<insert id="insertUser" parameterType="com.sikiedu.beans.User"> INSERT INTO user VALUES(null,#{username},#{userpassword},#{balance},#{grgisterdate}) </insert>
User user = new User(); user.setUsername("天猫"); user.setUserpassword("123456"); user.setBalance(Float.valueOf(1000)); user.setGrgisterdate(new SimpleDateFormat("yyyy-MM-dd").format(new Date(System.currentTimeMillis()))); sqlSession.insert("com.sikiedu.mapper.UserMapper.insertUser", user); sqlSession.commit();
♦ 删
<delete id="deleteUserById" parameterType="Integer"> DELETE FROM user WHERE id = #{id} </delete>
sqlSession.delete("com.sikiedu.mapper.UserMapper.deleteUserById", 100);
sqlSession.commit();
♦ 改
<update id="updateUser" parameterType="com.sikiedu.beans.User"> UPDATE user SET username = #{username} WHERE id = #{id} </update>
User user = new User(); user.setId(44); user.setUsername("阿羊"); sqlSession.update("com.sikiedu.mapper.UserMapper.updateUser", user); sqlSession.commit();
♦ 查
<!-- #{}占位符 尽量选用#{}来解决问题 --> <!-- ${}字符拼接 or1=1 容易被SQL注入 --> <select id="selectUserById" parameterType="Integer" resultType="com.sikiedu.beans.User"> SELECT * FROM user WHERE id = #{id} </select> <select id="selectUserLikeUsername" parameterType="String" resultType="User"> <!-- SELECT * FROM coke.user WHERE username LIKE '%${value}%' --> SELECT * FROM user WHERE username LIKE "%"#{username}"%" </select>
// 查询用户 // 操作数据库;参数1-要操作的sql语句;参数2-sql语句参数 User user = sqlSession.selectOne("com.sikiedu.mapper.UserMapper.selectUserById", 3); System.out.println(user); // 通过username模糊 查询用户 List<User> users = sqlSession.selectList("com.sikiedu.mapper.UserMapper.selectUserLikeUsername", "天"); for (User user : users) { System.out.println(user); }