mybatis+mysql環境下 uuid存儲優化

1問題

uuid採用char(32)或char(36)存儲的話,須要佔用32或36個字節。爲節省存儲空間,改成binary(16),佔用16字節。對於500W行的表,可節省7.4G的空間。java

mybatis中沒有默認的type handler來完成uuid類型<->binary類型的相互轉換,須要自定義一個type handler。下面就詳細地介紹如何實現。mysql

2 環境

mybatis 3.5.3sql

mysql 5.7.21session

java 8mybatis

3 自定義TypeHandler

 1 public class UuidHandler extends BaseTypeHandler<UUID> {  2 
 4  @Override  5     public void setNonNullParameter(PreparedStatement ps,  6                                     int columnIndex, UUID uuid,  7                                     JdbcType jdbcType) throws SQLException {  8 
 9         long mostBit = uuid.getMostSignificantBits(); 10         byte[] bytes = new byte[16]; 11         bytes[0] = (byte) ((mostBit >> 56) & 0xFF); 12         bytes[1] = (byte) ((mostBit >> 48) & 0xFF); 13         bytes[2] = (byte) ((mostBit >> 40) & 0xFF); 14         bytes[3] = (byte) ((mostBit >> 32) & 0xFF); 15         bytes[4] = (byte) ((mostBit >> 24) & 0xFF); 16         bytes[5] = (byte) ((mostBit >> 16) & 0xFF); 17         bytes[6] = (byte) ((mostBit >> 8) & 0xFF); 18         bytes[7] = (byte) (mostBit & 0xFF); 19         // 20         long leastBit = uuid.getLeastSignificantBits(); 21         bytes[8] = (byte) ((leastBit >> 56) & 0xFF); 22         bytes[9] = (byte) ((leastBit >> 48) & 0xFF); 23         bytes[10] = (byte) ((leastBit >> 40) & 0xFF); 24         bytes[11] = (byte) ((leastBit >> 32) & 0xFF); 25         bytes[12] = (byte) ((leastBit >> 24) & 0xFF); 26         bytes[13] = (byte) ((leastBit >> 16) & 0xFF); 27         bytes[14] = (byte) ((leastBit >> 8) & 0xFF); 28         bytes[15] = (byte) (leastBit & 0xFF); 29         // 30  ps.setBytes(columnIndex, bytes); 31  } 32 
33  @Override 34     public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 35         byte[] bytes = rs.getBytes(columnName); 36 
37         long mostBit = ((((long) bytes[0] & 0xFF) << 56) 38                 | (((long) bytes[1] & 0xFF) << 48) 39                 | (((long) bytes[2] & 0xFF) << 40) 40                 | (((long) bytes[3] & 0xFF) << 32) 41                 | (((long) bytes[4] & 0xFF) << 24) 42                 | (((long) bytes[5] & 0xFF) << 16) 43                 | (((long) bytes[6] & 0xFF) << 8) 44                 | (((long) bytes[7] & 0xFF))); 45 
46         long leastBit = ((((long) bytes[8] & 0xFF) << 56) 47                 | (((long) bytes[9] & 0xFF) << 48) 48                 | (((long) bytes[10] & 0xFF) << 40) 49                 | (((long) bytes[11] & 0xFF) << 32) 50                 | (((long) bytes[12] & 0xFF) << 24) 51                 | (((long) bytes[13] & 0xFF) << 16) 52                 | (((long) bytes[14] & 0xFF) << 8) 53                 | (((long) bytes[15] & 0xFF))); 54         return new UUID(mostBit, leastBit); 55  } 56 
57 
58  @Override 59     public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 60         //
61         return null; 62  } 63 
64  @Override 65     public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 66         //
67         return null; 68  } 69 }

 以 上代碼有2個關鍵點:app

一、在setNonNullParameter()方法中,將UUID轉換成byte[]。UUID使用128位(16字節)存儲,其中,uuid.getMostSignificantBits()返回高64位,uuid.getLeastSignificantBits()返回低64位。dom

二、在getNullableResult()方法中 , 將byte[]轉換成UUID。ide

 

4 測試

4.1 表

 1 CREATE TABLE `user_uuid` (
 2   `id` binary(16) NOT NULL,
 3   `name` varchar(10) DEFAULT NULL,
 4   PRIMARY KEY (`id`)
 5 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.2 實體

public class User { private UUID id; private String name;  // 略 }

4.3 mapper 

1 public interface UserMapper { 2 
3     void insert(User record); 4 
5  User selectByPrimaryKey(UUID id); 6 
7     List<User> selectAll(); 8 
9 }

 

 1     <insert id="insert" parameterType="leo.domain.User">
 2  insert into user_uuid (id, name)  3  values (#{id}, #{name})  4     </insert>
 5 
 6     <select id="selectByPrimaryKey" resultType="leo.domain.User"
 7  parameterType="java.util.UUID">
 8  select id, name  9  from user_uuid 10  where id = #{id} 11     </select>
12 
13 
14     <select id="selectAll" resultType="leo.domain.User">
15  select id, name 16  from user_uuid 17     </select>

4.4 配置

 1 <typeHandlers>
 2     <typeHandler handler="leo.handler.UuidHandler"/>
 3 </typeHandlers>
在typeHandlers節點中註冊UuidHandler

4.5 測試用例

 1 @FixMethodOrder(MethodSorters.NAME_ASCENDING)  2 public class UserMapperTest {  3 
 4  SqlSession session;  5  UserMapper mapper;  6 
 7  @Before  8     public void init() {  9         InputStream inputStream = App3_uuid.class.getResourceAsStream("/mybatis-config.xml"); 10         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 11         session = sqlSessionFactory.openSession(); 12         mapper = session.getMapper(UserMapper.class); 13  } 14 
15 
16  @Test 17     public void test1Insert() { 18         // 插入用戶1
19         UUID uuid1 = UUID.fromString("0eaa9bf6-0c70-4678-8658-8737d3a5eba1"); 20         User user1 = new User(); 21  user1.setId(uuid1); 22         user1.setName("用戶1"); 23  mapper.insert(user1); 24  session.commit(); 25 
26         // 插入用戶2
27         UUID uuid2 = UUID.fromString("0eaa9bf6-0c70-4678-8658-8737d3a5eba2"); 28         User user2 = new User(); 29  user2.setId(uuid2); 30         user2.setName("用戶2"); 31  mapper.insert(user2); 32  session.commit(); 33 
34  } 35 
36  @Test 37     public void test2SelectByPrimaryKey() { 38         UUID uuid1 = UUID.fromString("0eaa9bf6-0c70-4678-8658-8737d3a5eba1"); 39         User user1 = mapper.selectByPrimaryKey(uuid1); 40         System.out.println("user = " + user1); 41  } 42 
43  @Test 44     public void test3SelectAll() { 45         List<User> list = mapper.selectAll(); 46         System.out.println("list = " + list); 47 
48  } 49 }
相關文章
相關標籤/搜索